diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 497 |
1 files changed, 286 insertions, 211 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 089da5b5d20a..0f24cdf2cb13 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include "internal.h" | 55 | #include "internal.h" |
56 | #include "iostat.h" | 56 | #include "iostat.h" |
57 | #include "callback.h" | 57 | #include "callback.h" |
58 | #include "pnfs.h" | ||
58 | 59 | ||
59 | #define NFSDBG_FACILITY NFSDBG_PROC | 60 | #define NFSDBG_FACILITY NFSDBG_PROC |
60 | 61 | ||
@@ -129,7 +130,8 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE | |||
129 | | FATTR4_WORD0_MAXREAD | 130 | | FATTR4_WORD0_MAXREAD |
130 | | FATTR4_WORD0_MAXWRITE | 131 | | FATTR4_WORD0_MAXWRITE |
131 | | FATTR4_WORD0_LEASE_TIME, | 132 | | FATTR4_WORD0_LEASE_TIME, |
132 | 0 | 133 | FATTR4_WORD1_TIME_DELTA |
134 | | FATTR4_WORD1_FS_LAYOUT_TYPES | ||
133 | }; | 135 | }; |
134 | 136 | ||
135 | const u32 nfs4_fs_locations_bitmap[2] = { | 137 | const u32 nfs4_fs_locations_bitmap[2] = { |
@@ -255,9 +257,6 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
255 | nfs4_state_mark_reclaim_nograce(clp, state); | 257 | nfs4_state_mark_reclaim_nograce(clp, state); |
256 | goto do_state_recovery; | 258 | goto do_state_recovery; |
257 | case -NFS4ERR_STALE_STATEID: | 259 | case -NFS4ERR_STALE_STATEID: |
258 | if (state == NULL) | ||
259 | break; | ||
260 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
261 | case -NFS4ERR_STALE_CLIENTID: | 260 | case -NFS4ERR_STALE_CLIENTID: |
262 | case -NFS4ERR_EXPIRED: | 261 | case -NFS4ERR_EXPIRED: |
263 | goto do_state_recovery; | 262 | goto do_state_recovery; |
@@ -334,10 +333,12 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
334 | * Must be called while holding tbl->slot_tbl_lock | 333 | * Must be called while holding tbl->slot_tbl_lock |
335 | */ | 334 | */ |
336 | static void | 335 | static void |
337 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | 336 | nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot) |
338 | { | 337 | { |
338 | int free_slotid = free_slot - tbl->slots; | ||
339 | int slotid = free_slotid; | 339 | int slotid = free_slotid; |
340 | 340 | ||
341 | BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); | ||
341 | /* clear used bit in bitmap */ | 342 | /* clear used bit in bitmap */ |
342 | __clear_bit(slotid, tbl->used_slots); | 343 | __clear_bit(slotid, tbl->used_slots); |
343 | 344 | ||
@@ -379,7 +380,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
379 | struct nfs4_slot_table *tbl; | 380 | struct nfs4_slot_table *tbl; |
380 | 381 | ||
381 | tbl = &res->sr_session->fc_slot_table; | 382 | tbl = &res->sr_session->fc_slot_table; |
382 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 383 | if (!res->sr_slot) { |
383 | /* just wake up the next guy waiting since | 384 | /* just wake up the next guy waiting since |
384 | * we may have not consumed a slot after all */ | 385 | * we may have not consumed a slot after all */ |
385 | dprintk("%s: No slot\n", __func__); | 386 | dprintk("%s: No slot\n", __func__); |
@@ -387,17 +388,15 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
387 | } | 388 | } |
388 | 389 | ||
389 | spin_lock(&tbl->slot_tbl_lock); | 390 | spin_lock(&tbl->slot_tbl_lock); |
390 | nfs4_free_slot(tbl, res->sr_slotid); | 391 | nfs4_free_slot(tbl, res->sr_slot); |
391 | nfs41_check_drain_session_complete(res->sr_session); | 392 | nfs41_check_drain_session_complete(res->sr_session); |
392 | spin_unlock(&tbl->slot_tbl_lock); | 393 | spin_unlock(&tbl->slot_tbl_lock); |
393 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 394 | res->sr_slot = NULL; |
394 | } | 395 | } |
395 | 396 | ||
396 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | 397 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
397 | { | 398 | { |
398 | unsigned long timestamp; | 399 | unsigned long timestamp; |
399 | struct nfs4_slot_table *tbl; | ||
400 | struct nfs4_slot *slot; | ||
401 | struct nfs_client *clp; | 400 | struct nfs_client *clp; |
402 | 401 | ||
403 | /* | 402 | /* |
@@ -410,17 +409,14 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * | |||
410 | res->sr_status = NFS_OK; | 409 | res->sr_status = NFS_OK; |
411 | 410 | ||
412 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | 411 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ |
413 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 412 | if (!res->sr_slot) |
414 | goto out; | 413 | goto out; |
415 | 414 | ||
416 | tbl = &res->sr_session->fc_slot_table; | ||
417 | slot = tbl->slots + res->sr_slotid; | ||
418 | |||
419 | /* Check the SEQUENCE operation status */ | 415 | /* Check the SEQUENCE operation status */ |
420 | switch (res->sr_status) { | 416 | switch (res->sr_status) { |
421 | case 0: | 417 | case 0: |
422 | /* Update the slot's sequence and clientid lease timer */ | 418 | /* Update the slot's sequence and clientid lease timer */ |
423 | ++slot->seq_nr; | 419 | ++res->sr_slot->seq_nr; |
424 | timestamp = res->sr_renewal_time; | 420 | timestamp = res->sr_renewal_time; |
425 | clp = res->sr_session->clp; | 421 | clp = res->sr_session->clp; |
426 | do_renew_lease(clp, timestamp); | 422 | do_renew_lease(clp, timestamp); |
@@ -433,12 +429,14 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * | |||
433 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 | 429 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 |
434 | * of RFC5661. | 430 | * of RFC5661. |
435 | */ | 431 | */ |
436 | dprintk("%s: slot=%d seq=%d: Operation in progress\n", | 432 | dprintk("%s: slot=%td seq=%d: Operation in progress\n", |
437 | __func__, res->sr_slotid, slot->seq_nr); | 433 | __func__, |
434 | res->sr_slot - res->sr_session->fc_slot_table.slots, | ||
435 | res->sr_slot->seq_nr); | ||
438 | goto out_retry; | 436 | goto out_retry; |
439 | default: | 437 | default: |
440 | /* Just update the slot sequence no. */ | 438 | /* Just update the slot sequence no. */ |
441 | ++slot->seq_nr; | 439 | ++res->sr_slot->seq_nr; |
442 | } | 440 | } |
443 | out: | 441 | out: |
444 | /* The session may be reset by one of the error handlers. */ | 442 | /* The session may be reset by one of the error handlers. */ |
@@ -505,10 +503,9 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
505 | 503 | ||
506 | dprintk("--> %s\n", __func__); | 504 | dprintk("--> %s\n", __func__); |
507 | /* slot already allocated? */ | 505 | /* slot already allocated? */ |
508 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | 506 | if (res->sr_slot != NULL) |
509 | return 0; | 507 | return 0; |
510 | 508 | ||
511 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
512 | tbl = &session->fc_slot_table; | 509 | tbl = &session->fc_slot_table; |
513 | 510 | ||
514 | spin_lock(&tbl->slot_tbl_lock); | 511 | spin_lock(&tbl->slot_tbl_lock); |
@@ -550,7 +547,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
550 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | 547 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); |
551 | 548 | ||
552 | res->sr_session = session; | 549 | res->sr_session = session; |
553 | res->sr_slotid = slotid; | 550 | res->sr_slot = slot; |
554 | res->sr_renewal_time = jiffies; | 551 | res->sr_renewal_time = jiffies; |
555 | res->sr_status_flags = 0; | 552 | res->sr_status_flags = 0; |
556 | /* | 553 | /* |
@@ -576,8 +573,9 @@ int nfs4_setup_sequence(const struct nfs_server *server, | |||
576 | goto out; | 573 | goto out; |
577 | } | 574 | } |
578 | 575 | ||
579 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | 576 | dprintk("--> %s clp %p session %p sr_slot %td\n", |
580 | __func__, session->clp, session, res->sr_slotid); | 577 | __func__, session->clp, session, res->sr_slot ? |
578 | res->sr_slot - session->fc_slot_table.slots : -1); | ||
581 | 579 | ||
582 | ret = nfs41_setup_sequence(session, args, res, cache_reply, | 580 | ret = nfs41_setup_sequence(session, args, res, cache_reply, |
583 | task); | 581 | task); |
@@ -650,7 +648,7 @@ static int nfs4_call_sync_sequence(struct nfs_server *server, | |||
650 | .callback_data = &data | 648 | .callback_data = &data |
651 | }; | 649 | }; |
652 | 650 | ||
653 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 651 | res->sr_slot = NULL; |
654 | if (privileged) | 652 | if (privileged) |
655 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; | 653 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; |
656 | task = rpc_run_task(&task_setup); | 654 | task = rpc_run_task(&task_setup); |
@@ -735,7 +733,6 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
735 | p->o_res.server = p->o_arg.server; | 733 | p->o_res.server = p->o_arg.server; |
736 | nfs_fattr_init(&p->f_attr); | 734 | nfs_fattr_init(&p->f_attr); |
737 | nfs_fattr_init(&p->dir_attr); | 735 | nfs_fattr_init(&p->dir_attr); |
738 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
739 | } | 736 | } |
740 | 737 | ||
741 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 738 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
@@ -1120,6 +1117,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1120 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1117 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1121 | smp_rmb(); | 1118 | smp_rmb(); |
1122 | if (state->n_rdwr != 0) { | 1119 | if (state->n_rdwr != 0) { |
1120 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1123 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); | 1121 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); |
1124 | if (ret != 0) | 1122 | if (ret != 0) |
1125 | return ret; | 1123 | return ret; |
@@ -1127,6 +1125,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1127 | return -ESTALE; | 1125 | return -ESTALE; |
1128 | } | 1126 | } |
1129 | if (state->n_wronly != 0) { | 1127 | if (state->n_wronly != 0) { |
1128 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1130 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); | 1129 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); |
1131 | if (ret != 0) | 1130 | if (ret != 0) |
1132 | return ret; | 1131 | return ret; |
@@ -1134,6 +1133,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1134 | return -ESTALE; | 1133 | return -ESTALE; |
1135 | } | 1134 | } |
1136 | if (state->n_rdonly != 0) { | 1135 | if (state->n_rdonly != 0) { |
1136 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1137 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); | 1137 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); |
1138 | if (ret != 0) | 1138 | if (ret != 0) |
1139 | return ret; | 1139 | return ret; |
@@ -1188,7 +1188,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1188 | int err; | 1188 | int err; |
1189 | do { | 1189 | do { |
1190 | err = _nfs4_do_open_reclaim(ctx, state); | 1190 | err = _nfs4_do_open_reclaim(ctx, state); |
1191 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) | 1191 | if (err != -NFS4ERR_DELAY) |
1192 | break; | 1192 | break; |
1193 | nfs4_handle_exception(server, err, &exception); | 1193 | nfs4_handle_exception(server, err, &exception); |
1194 | } while (exception.retry); | 1194 | } while (exception.retry); |
@@ -1258,6 +1258,13 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
1258 | case -NFS4ERR_ADMIN_REVOKED: | 1258 | case -NFS4ERR_ADMIN_REVOKED: |
1259 | case -NFS4ERR_BAD_STATEID: | 1259 | case -NFS4ERR_BAD_STATEID: |
1260 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | 1260 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); |
1261 | case -EKEYEXPIRED: | ||
1262 | /* | ||
1263 | * User RPCSEC_GSS context has expired. | ||
1264 | * We cannot recover this stateid now, so | ||
1265 | * skip it and allow recovery thread to | ||
1266 | * proceed. | ||
1267 | */ | ||
1261 | case -ENOMEM: | 1268 | case -ENOMEM: |
1262 | err = 0; | 1269 | err = 0; |
1263 | goto out; | 1270 | goto out; |
@@ -1605,7 +1612,6 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state | |||
1605 | goto out; | 1612 | goto out; |
1606 | case -NFS4ERR_GRACE: | 1613 | case -NFS4ERR_GRACE: |
1607 | case -NFS4ERR_DELAY: | 1614 | case -NFS4ERR_DELAY: |
1608 | case -EKEYEXPIRED: | ||
1609 | nfs4_handle_exception(server, err, &exception); | 1615 | nfs4_handle_exception(server, err, &exception); |
1610 | err = 0; | 1616 | err = 0; |
1611 | } | 1617 | } |
@@ -1975,7 +1981,6 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i | |||
1975 | calldata->res.fattr = &calldata->fattr; | 1981 | calldata->res.fattr = &calldata->fattr; |
1976 | calldata->res.seqid = calldata->arg.seqid; | 1982 | calldata->res.seqid = calldata->arg.seqid; |
1977 | calldata->res.server = server; | 1983 | calldata->res.server = server; |
1978 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
1979 | path_get(path); | 1984 | path_get(path); |
1980 | calldata->path = *path; | 1985 | calldata->path = *path; |
1981 | 1986 | ||
@@ -1998,120 +2003,17 @@ out: | |||
1998 | return status; | 2003 | return status; |
1999 | } | 2004 | } |
2000 | 2005 | ||
2001 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode) | 2006 | static struct inode * |
2007 | nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr) | ||
2002 | { | 2008 | { |
2003 | struct file *filp; | ||
2004 | int ret; | ||
2005 | |||
2006 | /* If the open_intent is for execute, we have an extra check to make */ | ||
2007 | if (fmode & FMODE_EXEC) { | ||
2008 | ret = nfs_may_open(state->inode, | ||
2009 | state->owner->so_cred, | ||
2010 | nd->intent.open.flags); | ||
2011 | if (ret < 0) | ||
2012 | goto out_close; | ||
2013 | } | ||
2014 | filp = lookup_instantiate_filp(nd, path->dentry, NULL); | ||
2015 | if (!IS_ERR(filp)) { | ||
2016 | struct nfs_open_context *ctx; | ||
2017 | ctx = nfs_file_open_context(filp); | ||
2018 | ctx->state = state; | ||
2019 | return 0; | ||
2020 | } | ||
2021 | ret = PTR_ERR(filp); | ||
2022 | out_close: | ||
2023 | nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE)); | ||
2024 | return ret; | ||
2025 | } | ||
2026 | |||
2027 | struct dentry * | ||
2028 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
2029 | { | ||
2030 | struct path path = { | ||
2031 | .mnt = nd->path.mnt, | ||
2032 | .dentry = dentry, | ||
2033 | }; | ||
2034 | struct dentry *parent; | ||
2035 | struct iattr attr; | ||
2036 | struct rpc_cred *cred; | ||
2037 | struct nfs4_state *state; | 2009 | struct nfs4_state *state; |
2038 | struct dentry *res; | ||
2039 | int open_flags = nd->intent.open.flags; | ||
2040 | fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); | ||
2041 | |||
2042 | if (nd->flags & LOOKUP_CREATE) { | ||
2043 | attr.ia_mode = nd->intent.open.create_mode; | ||
2044 | attr.ia_valid = ATTR_MODE; | ||
2045 | if (!IS_POSIXACL(dir)) | ||
2046 | attr.ia_mode &= ~current_umask(); | ||
2047 | } else { | ||
2048 | open_flags &= ~O_EXCL; | ||
2049 | attr.ia_valid = 0; | ||
2050 | BUG_ON(open_flags & O_CREAT); | ||
2051 | } | ||
2052 | 2010 | ||
2053 | cred = rpc_lookup_cred(); | ||
2054 | if (IS_ERR(cred)) | ||
2055 | return (struct dentry *)cred; | ||
2056 | parent = dentry->d_parent; | ||
2057 | /* Protect against concurrent sillydeletes */ | 2011 | /* Protect against concurrent sillydeletes */ |
2058 | nfs_block_sillyrename(parent); | 2012 | state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred); |
2059 | state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred); | 2013 | if (IS_ERR(state)) |
2060 | put_rpccred(cred); | 2014 | return ERR_CAST(state); |
2061 | if (IS_ERR(state)) { | 2015 | ctx->state = state; |
2062 | if (PTR_ERR(state) == -ENOENT) { | 2016 | return igrab(state->inode); |
2063 | d_add(dentry, NULL); | ||
2064 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
2065 | } | ||
2066 | nfs_unblock_sillyrename(parent); | ||
2067 | return (struct dentry *)state; | ||
2068 | } | ||
2069 | res = d_add_unique(dentry, igrab(state->inode)); | ||
2070 | if (res != NULL) | ||
2071 | path.dentry = res; | ||
2072 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); | ||
2073 | nfs_unblock_sillyrename(parent); | ||
2074 | nfs4_intent_set_file(nd, &path, state, fmode); | ||
2075 | return res; | ||
2076 | } | ||
2077 | |||
2078 | int | ||
2079 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) | ||
2080 | { | ||
2081 | struct path path = { | ||
2082 | .mnt = nd->path.mnt, | ||
2083 | .dentry = dentry, | ||
2084 | }; | ||
2085 | struct rpc_cred *cred; | ||
2086 | struct nfs4_state *state; | ||
2087 | fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE); | ||
2088 | |||
2089 | cred = rpc_lookup_cred(); | ||
2090 | if (IS_ERR(cred)) | ||
2091 | return PTR_ERR(cred); | ||
2092 | state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred); | ||
2093 | put_rpccred(cred); | ||
2094 | if (IS_ERR(state)) { | ||
2095 | switch (PTR_ERR(state)) { | ||
2096 | case -EPERM: | ||
2097 | case -EACCES: | ||
2098 | case -EDQUOT: | ||
2099 | case -ENOSPC: | ||
2100 | case -EROFS: | ||
2101 | return PTR_ERR(state); | ||
2102 | default: | ||
2103 | goto out_drop; | ||
2104 | } | ||
2105 | } | ||
2106 | if (state->inode == dentry->d_inode) { | ||
2107 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
2108 | nfs4_intent_set_file(nd, &path, state, fmode); | ||
2109 | return 1; | ||
2110 | } | ||
2111 | nfs4_close_sync(&path, state, fmode); | ||
2112 | out_drop: | ||
2113 | d_drop(dentry); | ||
2114 | return 0; | ||
2115 | } | 2017 | } |
2116 | 2018 | ||
2117 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | 2019 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) |
@@ -2568,36 +2470,34 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
2568 | 2470 | ||
2569 | static int | 2471 | static int |
2570 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 2472 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
2571 | int flags, struct nameidata *nd) | 2473 | int flags, struct nfs_open_context *ctx) |
2572 | { | 2474 | { |
2573 | struct path path = { | 2475 | struct path my_path = { |
2574 | .mnt = nd->path.mnt, | ||
2575 | .dentry = dentry, | 2476 | .dentry = dentry, |
2576 | }; | 2477 | }; |
2478 | struct path *path = &my_path; | ||
2577 | struct nfs4_state *state; | 2479 | struct nfs4_state *state; |
2578 | struct rpc_cred *cred; | 2480 | struct rpc_cred *cred = NULL; |
2579 | fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE); | 2481 | fmode_t fmode = 0; |
2580 | int status = 0; | 2482 | int status = 0; |
2581 | 2483 | ||
2582 | cred = rpc_lookup_cred(); | 2484 | if (ctx != NULL) { |
2583 | if (IS_ERR(cred)) { | 2485 | cred = ctx->cred; |
2584 | status = PTR_ERR(cred); | 2486 | path = &ctx->path; |
2585 | goto out; | 2487 | fmode = ctx->mode; |
2586 | } | 2488 | } |
2587 | state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred); | 2489 | state = nfs4_do_open(dir, path, fmode, flags, sattr, cred); |
2588 | d_drop(dentry); | 2490 | d_drop(dentry); |
2589 | if (IS_ERR(state)) { | 2491 | if (IS_ERR(state)) { |
2590 | status = PTR_ERR(state); | 2492 | status = PTR_ERR(state); |
2591 | goto out_putcred; | 2493 | goto out; |
2592 | } | 2494 | } |
2593 | d_add(dentry, igrab(state->inode)); | 2495 | d_add(dentry, igrab(state->inode)); |
2594 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 2496 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
2595 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 2497 | if (ctx != NULL) |
2596 | status = nfs4_intent_set_file(nd, &path, state, fmode); | 2498 | ctx->state = state; |
2597 | else | 2499 | else |
2598 | nfs4_close_sync(&path, state, fmode); | 2500 | nfs4_close_sync(path, state, fmode); |
2599 | out_putcred: | ||
2600 | put_rpccred(cred); | ||
2601 | out: | 2501 | out: |
2602 | return status; | 2502 | return status; |
2603 | } | 2503 | } |
@@ -2655,6 +2555,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
2655 | 2555 | ||
2656 | args->bitmask = server->cache_consistency_bitmask; | 2556 | args->bitmask = server->cache_consistency_bitmask; |
2657 | res->server = server; | 2557 | res->server = server; |
2558 | res->seq_res.sr_slot = NULL; | ||
2658 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; | 2559 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; |
2659 | } | 2560 | } |
2660 | 2561 | ||
@@ -2671,18 +2572,46 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2671 | return 1; | 2572 | return 1; |
2672 | } | 2573 | } |
2673 | 2574 | ||
2575 | static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir) | ||
2576 | { | ||
2577 | struct nfs_server *server = NFS_SERVER(dir); | ||
2578 | struct nfs_renameargs *arg = msg->rpc_argp; | ||
2579 | struct nfs_renameres *res = msg->rpc_resp; | ||
2580 | |||
2581 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME]; | ||
2582 | arg->bitmask = server->attr_bitmask; | ||
2583 | res->server = server; | ||
2584 | } | ||
2585 | |||
2586 | static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | ||
2587 | struct inode *new_dir) | ||
2588 | { | ||
2589 | struct nfs_renameres *res = task->tk_msg.rpc_resp; | ||
2590 | |||
2591 | if (!nfs4_sequence_done(task, &res->seq_res)) | ||
2592 | return 0; | ||
2593 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | ||
2594 | return 0; | ||
2595 | |||
2596 | update_changeattr(old_dir, &res->old_cinfo); | ||
2597 | nfs_post_op_update_inode(old_dir, res->old_fattr); | ||
2598 | update_changeattr(new_dir, &res->new_cinfo); | ||
2599 | nfs_post_op_update_inode(new_dir, res->new_fattr); | ||
2600 | return 1; | ||
2601 | } | ||
2602 | |||
2674 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | 2603 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, |
2675 | struct inode *new_dir, struct qstr *new_name) | 2604 | struct inode *new_dir, struct qstr *new_name) |
2676 | { | 2605 | { |
2677 | struct nfs_server *server = NFS_SERVER(old_dir); | 2606 | struct nfs_server *server = NFS_SERVER(old_dir); |
2678 | struct nfs4_rename_arg arg = { | 2607 | struct nfs_renameargs arg = { |
2679 | .old_dir = NFS_FH(old_dir), | 2608 | .old_dir = NFS_FH(old_dir), |
2680 | .new_dir = NFS_FH(new_dir), | 2609 | .new_dir = NFS_FH(new_dir), |
2681 | .old_name = old_name, | 2610 | .old_name = old_name, |
2682 | .new_name = new_name, | 2611 | .new_name = new_name, |
2683 | .bitmask = server->attr_bitmask, | 2612 | .bitmask = server->attr_bitmask, |
2684 | }; | 2613 | }; |
2685 | struct nfs4_rename_res res = { | 2614 | struct nfs_renameres res = { |
2686 | .server = server, | 2615 | .server = server, |
2687 | }; | 2616 | }; |
2688 | struct rpc_message msg = { | 2617 | struct rpc_message msg = { |
@@ -2896,15 +2825,16 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
2896 | } | 2825 | } |
2897 | 2826 | ||
2898 | static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | 2827 | static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
2899 | u64 cookie, struct page *page, unsigned int count, int plus) | 2828 | u64 cookie, struct page **pages, unsigned int count, int plus) |
2900 | { | 2829 | { |
2901 | struct inode *dir = dentry->d_inode; | 2830 | struct inode *dir = dentry->d_inode; |
2902 | struct nfs4_readdir_arg args = { | 2831 | struct nfs4_readdir_arg args = { |
2903 | .fh = NFS_FH(dir), | 2832 | .fh = NFS_FH(dir), |
2904 | .pages = &page, | 2833 | .pages = pages, |
2905 | .pgbase = 0, | 2834 | .pgbase = 0, |
2906 | .count = count, | 2835 | .count = count, |
2907 | .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, | 2836 | .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, |
2837 | .plus = plus, | ||
2908 | }; | 2838 | }; |
2909 | struct nfs4_readdir_res res; | 2839 | struct nfs4_readdir_res res; |
2910 | struct rpc_message msg = { | 2840 | struct rpc_message msg = { |
@@ -2932,14 +2862,14 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2932 | } | 2862 | } |
2933 | 2863 | ||
2934 | static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | 2864 | static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
2935 | u64 cookie, struct page *page, unsigned int count, int plus) | 2865 | u64 cookie, struct page **pages, unsigned int count, int plus) |
2936 | { | 2866 | { |
2937 | struct nfs4_exception exception = { }; | 2867 | struct nfs4_exception exception = { }; |
2938 | int err; | 2868 | int err; |
2939 | do { | 2869 | do { |
2940 | err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), | 2870 | err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), |
2941 | _nfs4_proc_readdir(dentry, cred, cookie, | 2871 | _nfs4_proc_readdir(dentry, cred, cookie, |
2942 | page, count, plus), | 2872 | pages, count, plus), |
2943 | &exception); | 2873 | &exception); |
2944 | } while (exception.retry); | 2874 | } while (exception.retry); |
2945 | return err; | 2875 | return err; |
@@ -3490,9 +3420,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3490 | nfs4_state_mark_reclaim_nograce(clp, state); | 3420 | nfs4_state_mark_reclaim_nograce(clp, state); |
3491 | goto do_state_recovery; | 3421 | goto do_state_recovery; |
3492 | case -NFS4ERR_STALE_STATEID: | 3422 | case -NFS4ERR_STALE_STATEID: |
3493 | if (state == NULL) | ||
3494 | break; | ||
3495 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
3496 | case -NFS4ERR_STALE_CLIENTID: | 3423 | case -NFS4ERR_STALE_CLIENTID: |
3497 | case -NFS4ERR_EXPIRED: | 3424 | case -NFS4ERR_EXPIRED: |
3498 | goto do_state_recovery; | 3425 | goto do_state_recovery; |
@@ -3626,7 +3553,6 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
3626 | case -NFS4ERR_RESOURCE: | 3553 | case -NFS4ERR_RESOURCE: |
3627 | /* The IBM lawyers misread another document! */ | 3554 | /* The IBM lawyers misread another document! */ |
3628 | case -NFS4ERR_DELAY: | 3555 | case -NFS4ERR_DELAY: |
3629 | case -EKEYEXPIRED: | ||
3630 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | 3556 | err = nfs4_delay(clp->cl_rpcclient, &timeout); |
3631 | } | 3557 | } |
3632 | } while (err == 0); | 3558 | } while (err == 0); |
@@ -3721,7 +3647,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3721 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3647 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3722 | data->res.fattr = &data->fattr; | 3648 | data->res.fattr = &data->fattr; |
3723 | data->res.server = server; | 3649 | data->res.server = server; |
3724 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3725 | nfs_fattr_init(data->res.fattr); | 3650 | nfs_fattr_init(data->res.fattr); |
3726 | data->timestamp = jiffies; | 3651 | data->timestamp = jiffies; |
3727 | data->rpc_status = 0; | 3652 | data->rpc_status = 0; |
@@ -3874,7 +3799,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3874 | p->arg.fl = &p->fl; | 3799 | p->arg.fl = &p->fl; |
3875 | p->arg.seqid = seqid; | 3800 | p->arg.seqid = seqid; |
3876 | p->res.seqid = seqid; | 3801 | p->res.seqid = seqid; |
3877 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3878 | p->arg.stateid = &lsp->ls_stateid; | 3802 | p->arg.stateid = &lsp->ls_stateid; |
3879 | p->lsp = lsp; | 3803 | p->lsp = lsp; |
3880 | atomic_inc(&lsp->ls_count); | 3804 | atomic_inc(&lsp->ls_count); |
@@ -4054,7 +3978,6 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
4054 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3978 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
4055 | p->arg.lock_owner.id = lsp->ls_id.id; | 3979 | p->arg.lock_owner.id = lsp->ls_id.id; |
4056 | p->res.lock_seqid = p->arg.lock_seqid; | 3980 | p->res.lock_seqid = p->arg.lock_seqid; |
4057 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4058 | p->lsp = lsp; | 3981 | p->lsp = lsp; |
4059 | p->server = server; | 3982 | p->server = server; |
4060 | atomic_inc(&lsp->ls_count); | 3983 | atomic_inc(&lsp->ls_count); |
@@ -4241,7 +4164,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
4241 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4164 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4242 | return 0; | 4165 | return 0; |
4243 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); | 4166 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); |
4244 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) | 4167 | if (err != -NFS4ERR_DELAY) |
4245 | break; | 4168 | break; |
4246 | nfs4_handle_exception(server, err, &exception); | 4169 | nfs4_handle_exception(server, err, &exception); |
4247 | } while (exception.retry); | 4170 | } while (exception.retry); |
@@ -4266,7 +4189,6 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
4266 | goto out; | 4189 | goto out; |
4267 | case -NFS4ERR_GRACE: | 4190 | case -NFS4ERR_GRACE: |
4268 | case -NFS4ERR_DELAY: | 4191 | case -NFS4ERR_DELAY: |
4269 | case -EKEYEXPIRED: | ||
4270 | nfs4_handle_exception(server, err, &exception); | 4192 | nfs4_handle_exception(server, err, &exception); |
4271 | err = 0; | 4193 | err = 0; |
4272 | } | 4194 | } |
@@ -4412,13 +4334,21 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4412 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | 4334 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); |
4413 | err = 0; | 4335 | err = 0; |
4414 | goto out; | 4336 | goto out; |
4337 | case -EKEYEXPIRED: | ||
4338 | /* | ||
4339 | * User RPCSEC_GSS context has expired. | ||
4340 | * We cannot recover this stateid now, so | ||
4341 | * skip it and allow recovery thread to | ||
4342 | * proceed. | ||
4343 | */ | ||
4344 | err = 0; | ||
4345 | goto out; | ||
4415 | case -ENOMEM: | 4346 | case -ENOMEM: |
4416 | case -NFS4ERR_DENIED: | 4347 | case -NFS4ERR_DENIED: |
4417 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 4348 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
4418 | err = 0; | 4349 | err = 0; |
4419 | goto out; | 4350 | goto out; |
4420 | case -NFS4ERR_DELAY: | 4351 | case -NFS4ERR_DELAY: |
4421 | case -EKEYEXPIRED: | ||
4422 | break; | 4352 | break; |
4423 | } | 4353 | } |
4424 | err = nfs4_handle_exception(server, err, &exception); | 4354 | err = nfs4_handle_exception(server, err, &exception); |
@@ -4647,7 +4577,6 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4647 | switch (task->tk_status) { | 4577 | switch (task->tk_status) { |
4648 | case -NFS4ERR_DELAY: | 4578 | case -NFS4ERR_DELAY: |
4649 | case -NFS4ERR_GRACE: | 4579 | case -NFS4ERR_GRACE: |
4650 | case -EKEYEXPIRED: | ||
4651 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | 4580 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); |
4652 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | 4581 | rpc_delay(task, NFS4_POLL_RETRY_MIN); |
4653 | task->tk_status = 0; | 4582 | task->tk_status = 0; |
@@ -4687,7 +4616,6 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
4687 | }; | 4616 | }; |
4688 | int status; | 4617 | int status; |
4689 | 4618 | ||
4690 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4691 | dprintk("--> %s\n", __func__); | 4619 | dprintk("--> %s\n", __func__); |
4692 | task = rpc_run_task(&task_setup); | 4620 | task = rpc_run_task(&task_setup); |
4693 | 4621 | ||
@@ -4914,49 +4842,56 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4914 | args->bc_attrs.max_reqs); | 4842 | args->bc_attrs.max_reqs); |
4915 | } | 4843 | } |
4916 | 4844 | ||
4917 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | 4845 | static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session) |
4918 | { | 4846 | { |
4919 | if (rcvd <= sent) | 4847 | struct nfs4_channel_attrs *sent = &args->fc_attrs; |
4920 | return 0; | 4848 | struct nfs4_channel_attrs *rcvd = &session->fc_attrs; |
4921 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | 4849 | |
4922 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | 4850 | if (rcvd->headerpadsz > sent->headerpadsz) |
4923 | return -EINVAL; | 4851 | return -EINVAL; |
4852 | if (rcvd->max_resp_sz > sent->max_resp_sz) | ||
4853 | return -EINVAL; | ||
4854 | /* | ||
4855 | * Our requested max_ops is the minimum we need; we're not | ||
4856 | * prepared to break up compounds into smaller pieces than that. | ||
4857 | * So, no point even trying to continue if the server won't | ||
4858 | * cooperate: | ||
4859 | */ | ||
4860 | if (rcvd->max_ops < sent->max_ops) | ||
4861 | return -EINVAL; | ||
4862 | if (rcvd->max_reqs == 0) | ||
4863 | return -EINVAL; | ||
4864 | return 0; | ||
4924 | } | 4865 | } |
4925 | 4866 | ||
4926 | #define _verify_fore_channel_attr(_name_) \ | 4867 | static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session) |
4927 | _verify_channel_attr("fore", #_name_, \ | 4868 | { |
4928 | args->fc_attrs._name_, \ | 4869 | struct nfs4_channel_attrs *sent = &args->bc_attrs; |
4929 | session->fc_attrs._name_) | 4870 | struct nfs4_channel_attrs *rcvd = &session->bc_attrs; |
4930 | 4871 | ||
4931 | #define _verify_back_channel_attr(_name_) \ | 4872 | if (rcvd->max_rqst_sz > sent->max_rqst_sz) |
4932 | _verify_channel_attr("back", #_name_, \ | 4873 | return -EINVAL; |
4933 | args->bc_attrs._name_, \ | 4874 | if (rcvd->max_resp_sz < sent->max_resp_sz) |
4934 | session->bc_attrs._name_) | 4875 | return -EINVAL; |
4876 | if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached) | ||
4877 | return -EINVAL; | ||
4878 | /* These would render the backchannel useless: */ | ||
4879 | if (rcvd->max_ops == 0) | ||
4880 | return -EINVAL; | ||
4881 | if (rcvd->max_reqs == 0) | ||
4882 | return -EINVAL; | ||
4883 | return 0; | ||
4884 | } | ||
4935 | 4885 | ||
4936 | /* | ||
4937 | * The server is not allowed to increase the fore channel header pad size, | ||
4938 | * maximum response size, or maximum number of operations. | ||
4939 | * | ||
4940 | * The back channel attributes are only negotiatied down: We send what the | ||
4941 | * (back channel) server insists upon. | ||
4942 | */ | ||
4943 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | 4886 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, |
4944 | struct nfs4_session *session) | 4887 | struct nfs4_session *session) |
4945 | { | 4888 | { |
4946 | int ret = 0; | 4889 | int ret; |
4947 | |||
4948 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
4949 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
4950 | ret |= _verify_fore_channel_attr(max_ops); | ||
4951 | |||
4952 | ret |= _verify_back_channel_attr(headerpadsz); | ||
4953 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
4954 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
4955 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
4956 | ret |= _verify_back_channel_attr(max_ops); | ||
4957 | ret |= _verify_back_channel_attr(max_reqs); | ||
4958 | 4890 | ||
4959 | return ret; | 4891 | ret = nfs4_verify_fore_channel_attrs(args, session); |
4892 | if (ret) | ||
4893 | return ret; | ||
4894 | return nfs4_verify_back_channel_attrs(args, session); | ||
4960 | } | 4895 | } |
4961 | 4896 | ||
4962 | static int _nfs4_proc_create_session(struct nfs_client *clp) | 4897 | static int _nfs4_proc_create_session(struct nfs_client *clp) |
@@ -5111,7 +5046,6 @@ static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client | |||
5111 | { | 5046 | { |
5112 | switch(task->tk_status) { | 5047 | switch(task->tk_status) { |
5113 | case -NFS4ERR_DELAY: | 5048 | case -NFS4ERR_DELAY: |
5114 | case -EKEYEXPIRED: | ||
5115 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 5049 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
5116 | return -EAGAIN; | 5050 | return -EAGAIN; |
5117 | default: | 5051 | default: |
@@ -5180,12 +5114,11 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ | |||
5180 | 5114 | ||
5181 | if (!atomic_inc_not_zero(&clp->cl_count)) | 5115 | if (!atomic_inc_not_zero(&clp->cl_count)) |
5182 | return ERR_PTR(-EIO); | 5116 | return ERR_PTR(-EIO); |
5183 | calldata = kmalloc(sizeof(*calldata), GFP_NOFS); | 5117 | calldata = kzalloc(sizeof(*calldata), GFP_NOFS); |
5184 | if (calldata == NULL) { | 5118 | if (calldata == NULL) { |
5185 | nfs_put_client(clp); | 5119 | nfs_put_client(clp); |
5186 | return ERR_PTR(-ENOMEM); | 5120 | return ERR_PTR(-ENOMEM); |
5187 | } | 5121 | } |
5188 | calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
5189 | msg.rpc_argp = &calldata->args; | 5122 | msg.rpc_argp = &calldata->args; |
5190 | msg.rpc_resp = &calldata->res; | 5123 | msg.rpc_resp = &calldata->res; |
5191 | calldata->clp = clp; | 5124 | calldata->clp = clp; |
@@ -5254,7 +5187,6 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf | |||
5254 | case -NFS4ERR_WRONG_CRED: /* What to do here? */ | 5187 | case -NFS4ERR_WRONG_CRED: /* What to do here? */ |
5255 | break; | 5188 | break; |
5256 | case -NFS4ERR_DELAY: | 5189 | case -NFS4ERR_DELAY: |
5257 | case -EKEYEXPIRED: | ||
5258 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 5190 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
5259 | return -EAGAIN; | 5191 | return -EAGAIN; |
5260 | default: | 5192 | default: |
@@ -5317,7 +5249,6 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
5317 | goto out; | 5249 | goto out; |
5318 | calldata->clp = clp; | 5250 | calldata->clp = clp; |
5319 | calldata->arg.one_fs = 0; | 5251 | calldata->arg.one_fs = 0; |
5320 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
5321 | 5252 | ||
5322 | msg.rpc_argp = &calldata->arg; | 5253 | msg.rpc_argp = &calldata->arg; |
5323 | msg.rpc_resp = &calldata->res; | 5254 | msg.rpc_resp = &calldata->res; |
@@ -5333,6 +5264,147 @@ out: | |||
5333 | dprintk("<-- %s status=%d\n", __func__, status); | 5264 | dprintk("<-- %s status=%d\n", __func__, status); |
5334 | return status; | 5265 | return status; |
5335 | } | 5266 | } |
5267 | |||
5268 | static void | ||
5269 | nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) | ||
5270 | { | ||
5271 | struct nfs4_layoutget *lgp = calldata; | ||
5272 | struct inode *ino = lgp->args.inode; | ||
5273 | struct nfs_server *server = NFS_SERVER(ino); | ||
5274 | |||
5275 | dprintk("--> %s\n", __func__); | ||
5276 | if (nfs4_setup_sequence(server, &lgp->args.seq_args, | ||
5277 | &lgp->res.seq_res, 0, task)) | ||
5278 | return; | ||
5279 | rpc_call_start(task); | ||
5280 | } | ||
5281 | |||
5282 | static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | ||
5283 | { | ||
5284 | struct nfs4_layoutget *lgp = calldata; | ||
5285 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | ||
5286 | |||
5287 | dprintk("--> %s\n", __func__); | ||
5288 | |||
5289 | if (!nfs4_sequence_done(task, &lgp->res.seq_res)) | ||
5290 | return; | ||
5291 | |||
5292 | switch (task->tk_status) { | ||
5293 | case 0: | ||
5294 | break; | ||
5295 | case -NFS4ERR_LAYOUTTRYLATER: | ||
5296 | case -NFS4ERR_RECALLCONFLICT: | ||
5297 | task->tk_status = -NFS4ERR_DELAY; | ||
5298 | /* Fall through */ | ||
5299 | default: | ||
5300 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { | ||
5301 | rpc_restart_call_prepare(task); | ||
5302 | return; | ||
5303 | } | ||
5304 | } | ||
5305 | lgp->status = task->tk_status; | ||
5306 | dprintk("<-- %s\n", __func__); | ||
5307 | } | ||
5308 | |||
5309 | static void nfs4_layoutget_release(void *calldata) | ||
5310 | { | ||
5311 | struct nfs4_layoutget *lgp = calldata; | ||
5312 | |||
5313 | dprintk("--> %s\n", __func__); | ||
5314 | put_layout_hdr(lgp->args.inode); | ||
5315 | if (lgp->res.layout.buf != NULL) | ||
5316 | free_page((unsigned long) lgp->res.layout.buf); | ||
5317 | put_nfs_open_context(lgp->args.ctx); | ||
5318 | kfree(calldata); | ||
5319 | dprintk("<-- %s\n", __func__); | ||
5320 | } | ||
5321 | |||
5322 | static const struct rpc_call_ops nfs4_layoutget_call_ops = { | ||
5323 | .rpc_call_prepare = nfs4_layoutget_prepare, | ||
5324 | .rpc_call_done = nfs4_layoutget_done, | ||
5325 | .rpc_release = nfs4_layoutget_release, | ||
5326 | }; | ||
5327 | |||
5328 | int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | ||
5329 | { | ||
5330 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | ||
5331 | struct rpc_task *task; | ||
5332 | struct rpc_message msg = { | ||
5333 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], | ||
5334 | .rpc_argp = &lgp->args, | ||
5335 | .rpc_resp = &lgp->res, | ||
5336 | }; | ||
5337 | struct rpc_task_setup task_setup_data = { | ||
5338 | .rpc_client = server->client, | ||
5339 | .rpc_message = &msg, | ||
5340 | .callback_ops = &nfs4_layoutget_call_ops, | ||
5341 | .callback_data = lgp, | ||
5342 | .flags = RPC_TASK_ASYNC, | ||
5343 | }; | ||
5344 | int status = 0; | ||
5345 | |||
5346 | dprintk("--> %s\n", __func__); | ||
5347 | |||
5348 | lgp->res.layout.buf = (void *)__get_free_page(GFP_NOFS); | ||
5349 | if (lgp->res.layout.buf == NULL) { | ||
5350 | nfs4_layoutget_release(lgp); | ||
5351 | return -ENOMEM; | ||
5352 | } | ||
5353 | |||
5354 | lgp->res.seq_res.sr_slot = NULL; | ||
5355 | task = rpc_run_task(&task_setup_data); | ||
5356 | if (IS_ERR(task)) | ||
5357 | return PTR_ERR(task); | ||
5358 | status = nfs4_wait_for_completion_rpc_task(task); | ||
5359 | if (status != 0) | ||
5360 | goto out; | ||
5361 | status = lgp->status; | ||
5362 | if (status != 0) | ||
5363 | goto out; | ||
5364 | status = pnfs_layout_process(lgp); | ||
5365 | out: | ||
5366 | rpc_put_task(task); | ||
5367 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5368 | return status; | ||
5369 | } | ||
5370 | |||
5371 | static int | ||
5372 | _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | ||
5373 | { | ||
5374 | struct nfs4_getdeviceinfo_args args = { | ||
5375 | .pdev = pdev, | ||
5376 | }; | ||
5377 | struct nfs4_getdeviceinfo_res res = { | ||
5378 | .pdev = pdev, | ||
5379 | }; | ||
5380 | struct rpc_message msg = { | ||
5381 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO], | ||
5382 | .rpc_argp = &args, | ||
5383 | .rpc_resp = &res, | ||
5384 | }; | ||
5385 | int status; | ||
5386 | |||
5387 | dprintk("--> %s\n", __func__); | ||
5388 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | ||
5389 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5390 | |||
5391 | return status; | ||
5392 | } | ||
5393 | |||
5394 | int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | ||
5395 | { | ||
5396 | struct nfs4_exception exception = { }; | ||
5397 | int err; | ||
5398 | |||
5399 | do { | ||
5400 | err = nfs4_handle_exception(server, | ||
5401 | _nfs4_proc_getdeviceinfo(server, pdev), | ||
5402 | &exception); | ||
5403 | } while (exception.retry); | ||
5404 | return err; | ||
5405 | } | ||
5406 | EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo); | ||
5407 | |||
5336 | #endif /* CONFIG_NFS_V4_1 */ | 5408 | #endif /* CONFIG_NFS_V4_1 */ |
5337 | 5409 | ||
5338 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5410 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -5443,6 +5515,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
5443 | .unlink_setup = nfs4_proc_unlink_setup, | 5515 | .unlink_setup = nfs4_proc_unlink_setup, |
5444 | .unlink_done = nfs4_proc_unlink_done, | 5516 | .unlink_done = nfs4_proc_unlink_done, |
5445 | .rename = nfs4_proc_rename, | 5517 | .rename = nfs4_proc_rename, |
5518 | .rename_setup = nfs4_proc_rename_setup, | ||
5519 | .rename_done = nfs4_proc_rename_done, | ||
5446 | .link = nfs4_proc_link, | 5520 | .link = nfs4_proc_link, |
5447 | .symlink = nfs4_proc_symlink, | 5521 | .symlink = nfs4_proc_symlink, |
5448 | .mkdir = nfs4_proc_mkdir, | 5522 | .mkdir = nfs4_proc_mkdir, |
@@ -5463,6 +5537,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
5463 | .lock = nfs4_proc_lock, | 5537 | .lock = nfs4_proc_lock, |
5464 | .clear_acl_cache = nfs4_zap_acl_attr, | 5538 | .clear_acl_cache = nfs4_zap_acl_attr, |
5465 | .close_context = nfs4_close_context, | 5539 | .close_context = nfs4_close_context, |
5540 | .open_context = nfs4_atomic_open, | ||
5466 | }; | 5541 | }; |
5467 | 5542 | ||
5468 | /* | 5543 | /* |