diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/current_stateid.h | 28 | ||||
-rw-r--r-- | fs/nfsd/export.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 115 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 309 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 132 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 44 | ||||
-rw-r--r-- | fs/nfsd/state.h | 21 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 33 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 2 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 34 |
11 files changed, 518 insertions, 204 deletions
diff --git a/fs/nfsd/current_stateid.h b/fs/nfsd/current_stateid.h new file mode 100644 index 000000000000..4123551208d8 --- /dev/null +++ b/fs/nfsd/current_stateid.h | |||
@@ -0,0 +1,28 @@ | |||
1 | #ifndef _NFSD4_CURRENT_STATE_H | ||
2 | #define _NFSD4_CURRENT_STATE_H | ||
3 | |||
4 | #include "state.h" | ||
5 | #include "xdr4.h" | ||
6 | |||
7 | extern void clear_current_stateid(struct nfsd4_compound_state *cstate); | ||
8 | /* | ||
9 | * functions to set current state id | ||
10 | */ | ||
11 | extern void nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *); | ||
12 | extern void nfsd4_set_openstateid(struct nfsd4_compound_state *, struct nfsd4_open *); | ||
13 | extern void nfsd4_set_lockstateid(struct nfsd4_compound_state *, struct nfsd4_lock *); | ||
14 | extern void nfsd4_set_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *); | ||
15 | |||
16 | /* | ||
17 | * functions to consume current state id | ||
18 | */ | ||
19 | extern void nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *); | ||
20 | extern void nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *, struct nfsd4_delegreturn *); | ||
21 | extern void nfsd4_get_freestateid(struct nfsd4_compound_state *, struct nfsd4_free_stateid *); | ||
22 | extern void nfsd4_get_setattrstateid(struct nfsd4_compound_state *, struct nfsd4_setattr *); | ||
23 | extern void nfsd4_get_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *); | ||
24 | extern void nfsd4_get_lockustateid(struct nfsd4_compound_state *, struct nfsd4_locku *); | ||
25 | extern void nfsd4_get_readstateid(struct nfsd4_compound_state *, struct nfsd4_read *); | ||
26 | extern void nfsd4_get_writestateid(struct nfsd4_compound_state *, struct nfsd4_write *); | ||
27 | |||
28 | #endif /* _NFSD4_CURRENT_STATE_H */ | ||
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index cf8a6bd062fa..8e9689abbc0c 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -87,7 +87,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
87 | struct svc_expkey key; | 87 | struct svc_expkey key; |
88 | struct svc_expkey *ek = NULL; | 88 | struct svc_expkey *ek = NULL; |
89 | 89 | ||
90 | if (mlen < 1 || mesg[mlen-1] != '\n') | 90 | if (mesg[mlen - 1] != '\n') |
91 | return -EINVAL; | 91 | return -EINVAL; |
92 | mesg[mlen-1] = 0; | 92 | mesg[mlen-1] = 0; |
93 | 93 | ||
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 0e262f32ac41..cf6e4190e41c 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -986,7 +986,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) | |||
986 | 986 | ||
987 | err = setup_callback_client(clp, &conn, ses); | 987 | err = setup_callback_client(clp, &conn, ses); |
988 | if (err) { | 988 | if (err) { |
989 | warn_no_callback_path(clp, err); | 989 | nfsd4_mark_cb_down(clp, err); |
990 | return; | 990 | return; |
991 | } | 991 | } |
992 | /* Yay, the callback channel's back! Restart any callbacks: */ | 992 | /* Yay, the callback channel's back! Restart any callbacks: */ |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 896da74ec563..2a9036670b8f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "cache.h" | 39 | #include "cache.h" |
40 | #include "xdr4.h" | 40 | #include "xdr4.h" |
41 | #include "vfs.h" | 41 | #include "vfs.h" |
42 | #include "current_stateid.h" | ||
42 | 43 | ||
43 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 44 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
44 | 45 | ||
@@ -192,10 +193,13 @@ static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) | |||
192 | static __be32 | 193 | static __be32 |
193 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 194 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
194 | { | 195 | { |
195 | struct svc_fh resfh; | 196 | struct svc_fh *resfh; |
196 | __be32 status; | 197 | __be32 status; |
197 | 198 | ||
198 | fh_init(&resfh, NFS4_FHSIZE); | 199 | resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); |
200 | if (!resfh) | ||
201 | return nfserr_jukebox; | ||
202 | fh_init(resfh, NFS4_FHSIZE); | ||
199 | open->op_truncate = 0; | 203 | open->op_truncate = 0; |
200 | 204 | ||
201 | if (open->op_create) { | 205 | if (open->op_create) { |
@@ -220,7 +224,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
220 | */ | 224 | */ |
221 | status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, | 225 | status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, |
222 | open->op_fname.len, &open->op_iattr, | 226 | open->op_fname.len, &open->op_iattr, |
223 | &resfh, open->op_createmode, | 227 | resfh, open->op_createmode, |
224 | (u32 *)open->op_verf.data, | 228 | (u32 *)open->op_verf.data, |
225 | &open->op_truncate, &open->op_created); | 229 | &open->op_truncate, &open->op_created); |
226 | 230 | ||
@@ -234,30 +238,29 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
234 | FATTR4_WORD1_TIME_MODIFY); | 238 | FATTR4_WORD1_TIME_MODIFY); |
235 | } else { | 239 | } else { |
236 | status = nfsd_lookup(rqstp, current_fh, | 240 | status = nfsd_lookup(rqstp, current_fh, |
237 | open->op_fname.data, open->op_fname.len, &resfh); | 241 | open->op_fname.data, open->op_fname.len, resfh); |
238 | fh_unlock(current_fh); | 242 | fh_unlock(current_fh); |
239 | if (status) | 243 | if (status) |
240 | goto out; | 244 | goto out; |
241 | status = nfsd_check_obj_isreg(&resfh); | 245 | status = nfsd_check_obj_isreg(resfh); |
242 | } | 246 | } |
243 | if (status) | 247 | if (status) |
244 | goto out; | 248 | goto out; |
245 | 249 | ||
246 | if (is_create_with_attrs(open) && open->op_acl != NULL) | 250 | if (is_create_with_attrs(open) && open->op_acl != NULL) |
247 | do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval); | 251 | do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval); |
248 | |||
249 | set_change_info(&open->op_cinfo, current_fh); | ||
250 | fh_dup2(current_fh, &resfh); | ||
251 | 252 | ||
252 | /* set reply cache */ | 253 | /* set reply cache */ |
253 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, | 254 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
254 | &resfh.fh_handle); | 255 | &resfh->fh_handle); |
255 | if (!open->op_created) | 256 | if (!open->op_created) |
256 | status = do_open_permission(rqstp, current_fh, open, | 257 | status = do_open_permission(rqstp, resfh, open, |
257 | NFSD_MAY_NOP); | 258 | NFSD_MAY_NOP); |
258 | 259 | set_change_info(&open->op_cinfo, current_fh); | |
260 | fh_dup2(current_fh, resfh); | ||
259 | out: | 261 | out: |
260 | fh_put(&resfh); | 262 | fh_put(resfh); |
263 | kfree(resfh); | ||
261 | return status; | 264 | return status; |
262 | } | 265 | } |
263 | 266 | ||
@@ -310,9 +313,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
310 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) | 313 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) |
311 | return nfserr_inval; | 314 | return nfserr_inval; |
312 | 315 | ||
313 | /* We don't yet support WANT bits: */ | ||
314 | open->op_share_access &= NFS4_SHARE_ACCESS_MASK; | ||
315 | |||
316 | open->op_created = 0; | 316 | open->op_created = 0; |
317 | /* | 317 | /* |
318 | * RFC5661 18.51.3 | 318 | * RFC5661 18.51.3 |
@@ -452,6 +452,10 @@ nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
452 | return nfserr_restorefh; | 452 | return nfserr_restorefh; |
453 | 453 | ||
454 | fh_dup2(&cstate->current_fh, &cstate->save_fh); | 454 | fh_dup2(&cstate->current_fh, &cstate->save_fh); |
455 | if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) { | ||
456 | memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t)); | ||
457 | SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); | ||
458 | } | ||
455 | return nfs_ok; | 459 | return nfs_ok; |
456 | } | 460 | } |
457 | 461 | ||
@@ -463,6 +467,10 @@ nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
463 | return nfserr_nofilehandle; | 467 | return nfserr_nofilehandle; |
464 | 468 | ||
465 | fh_dup2(&cstate->save_fh, &cstate->current_fh); | 469 | fh_dup2(&cstate->save_fh, &cstate->current_fh); |
470 | if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) { | ||
471 | memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t)); | ||
472 | SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG); | ||
473 | } | ||
466 | return nfs_ok; | 474 | return nfs_ok; |
467 | } | 475 | } |
468 | 476 | ||
@@ -481,14 +489,20 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
481 | &access->ac_supported); | 489 | &access->ac_supported); |
482 | } | 490 | } |
483 | 491 | ||
492 | static void gen_boot_verifier(nfs4_verifier *verifier) | ||
493 | { | ||
494 | __be32 verf[2]; | ||
495 | |||
496 | verf[0] = (__be32)nfssvc_boot.tv_sec; | ||
497 | verf[1] = (__be32)nfssvc_boot.tv_usec; | ||
498 | memcpy(verifier->data, verf, sizeof(verifier->data)); | ||
499 | } | ||
500 | |||
484 | static __be32 | 501 | static __be32 |
485 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 502 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
486 | struct nfsd4_commit *commit) | 503 | struct nfsd4_commit *commit) |
487 | { | 504 | { |
488 | u32 *p = (u32 *)commit->co_verf.data; | 505 | gen_boot_verifier(&commit->co_verf); |
489 | *p++ = nfssvc_boot.tv_sec; | ||
490 | *p++ = nfssvc_boot.tv_usec; | ||
491 | |||
492 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, | 506 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, |
493 | commit->co_count); | 507 | commit->co_count); |
494 | } | 508 | } |
@@ -865,7 +879,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
865 | { | 879 | { |
866 | stateid_t *stateid = &write->wr_stateid; | 880 | stateid_t *stateid = &write->wr_stateid; |
867 | struct file *filp = NULL; | 881 | struct file *filp = NULL; |
868 | u32 *p; | ||
869 | __be32 status = nfs_ok; | 882 | __be32 status = nfs_ok; |
870 | unsigned long cnt; | 883 | unsigned long cnt; |
871 | 884 | ||
@@ -887,9 +900,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
887 | 900 | ||
888 | cnt = write->wr_buflen; | 901 | cnt = write->wr_buflen; |
889 | write->wr_how_written = write->wr_stable_how; | 902 | write->wr_how_written = write->wr_stable_how; |
890 | p = (u32 *)write->wr_verifier.data; | 903 | gen_boot_verifier(&write->wr_verifier); |
891 | *p++ = nfssvc_boot.tv_sec; | ||
892 | *p++ = nfssvc_boot.tv_usec; | ||
893 | 904 | ||
894 | status = nfsd_write(rqstp, &cstate->current_fh, filp, | 905 | status = nfsd_write(rqstp, &cstate->current_fh, filp, |
895 | write->wr_offset, rqstp->rq_vec, write->wr_vlen, | 906 | write->wr_offset, rqstp->rq_vec, write->wr_vlen, |
@@ -1000,6 +1011,8 @@ static inline void nfsd4_increment_op_stats(u32 opnum) | |||
1000 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | 1011 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, |
1001 | void *); | 1012 | void *); |
1002 | typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op); | 1013 | typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op); |
1014 | typedef void(*stateid_setter)(struct nfsd4_compound_state *, void *); | ||
1015 | typedef void(*stateid_getter)(struct nfsd4_compound_state *, void *); | ||
1003 | 1016 | ||
1004 | enum nfsd4_op_flags { | 1017 | enum nfsd4_op_flags { |
1005 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ | 1018 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ |
@@ -1025,6 +1038,10 @@ enum nfsd4_op_flags { | |||
1025 | * the v4.0 case). | 1038 | * the v4.0 case). |
1026 | */ | 1039 | */ |
1027 | OP_CACHEME = 1 << 6, | 1040 | OP_CACHEME = 1 << 6, |
1041 | /* | ||
1042 | * These are ops which clear current state id. | ||
1043 | */ | ||
1044 | OP_CLEAR_STATEID = 1 << 7, | ||
1028 | }; | 1045 | }; |
1029 | 1046 | ||
1030 | struct nfsd4_operation { | 1047 | struct nfsd4_operation { |
@@ -1033,11 +1050,15 @@ struct nfsd4_operation { | |||
1033 | char *op_name; | 1050 | char *op_name; |
1034 | /* Try to get response size before operation */ | 1051 | /* Try to get response size before operation */ |
1035 | nfsd4op_rsize op_rsize_bop; | 1052 | nfsd4op_rsize op_rsize_bop; |
1053 | stateid_setter op_get_currentstateid; | ||
1054 | stateid_getter op_set_currentstateid; | ||
1036 | }; | 1055 | }; |
1037 | 1056 | ||
1038 | static struct nfsd4_operation nfsd4_ops[]; | 1057 | static struct nfsd4_operation nfsd4_ops[]; |
1039 | 1058 | ||
1059 | #ifdef NFSD_DEBUG | ||
1040 | static const char *nfsd4_op_name(unsigned opnum); | 1060 | static const char *nfsd4_op_name(unsigned opnum); |
1061 | #endif | ||
1041 | 1062 | ||
1042 | /* | 1063 | /* |
1043 | * Enforce NFSv4.1 COMPOUND ordering rules: | 1064 | * Enforce NFSv4.1 COMPOUND ordering rules: |
@@ -1215,13 +1236,23 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1215 | if (op->status) | 1236 | if (op->status) |
1216 | goto encode_op; | 1237 | goto encode_op; |
1217 | 1238 | ||
1218 | if (opdesc->op_func) | 1239 | if (opdesc->op_func) { |
1240 | if (opdesc->op_get_currentstateid) | ||
1241 | opdesc->op_get_currentstateid(cstate, &op->u); | ||
1219 | op->status = opdesc->op_func(rqstp, cstate, &op->u); | 1242 | op->status = opdesc->op_func(rqstp, cstate, &op->u); |
1220 | else | 1243 | } else |
1221 | BUG_ON(op->status == nfs_ok); | 1244 | BUG_ON(op->status == nfs_ok); |
1222 | 1245 | ||
1223 | if (!op->status && need_wrongsec_check(rqstp)) | 1246 | if (!op->status) { |
1224 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); | 1247 | if (opdesc->op_set_currentstateid) |
1248 | opdesc->op_set_currentstateid(cstate, &op->u); | ||
1249 | |||
1250 | if (opdesc->op_flags & OP_CLEAR_STATEID) | ||
1251 | clear_current_stateid(cstate); | ||
1252 | |||
1253 | if (need_wrongsec_check(rqstp)) | ||
1254 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); | ||
1255 | } | ||
1225 | 1256 | ||
1226 | encode_op: | 1257 | encode_op: |
1227 | /* Only from SEQUENCE */ | 1258 | /* Only from SEQUENCE */ |
@@ -1413,6 +1444,8 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1413 | .op_flags = OP_MODIFIES_SOMETHING, | 1444 | .op_flags = OP_MODIFIES_SOMETHING, |
1414 | .op_name = "OP_CLOSE", | 1445 | .op_name = "OP_CLOSE", |
1415 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | 1446 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, |
1447 | .op_get_currentstateid = (stateid_getter)nfsd4_get_closestateid, | ||
1448 | .op_set_currentstateid = (stateid_setter)nfsd4_set_closestateid, | ||
1416 | }, | 1449 | }, |
1417 | [OP_COMMIT] = { | 1450 | [OP_COMMIT] = { |
1418 | .op_func = (nfsd4op_func)nfsd4_commit, | 1451 | .op_func = (nfsd4op_func)nfsd4_commit, |
@@ -1422,7 +1455,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1422 | }, | 1455 | }, |
1423 | [OP_CREATE] = { | 1456 | [OP_CREATE] = { |
1424 | .op_func = (nfsd4op_func)nfsd4_create, | 1457 | .op_func = (nfsd4op_func)nfsd4_create, |
1425 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | 1458 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID, |
1426 | .op_name = "OP_CREATE", | 1459 | .op_name = "OP_CREATE", |
1427 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize, | 1460 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize, |
1428 | }, | 1461 | }, |
@@ -1431,6 +1464,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1431 | .op_flags = OP_MODIFIES_SOMETHING, | 1464 | .op_flags = OP_MODIFIES_SOMETHING, |
1432 | .op_name = "OP_DELEGRETURN", | 1465 | .op_name = "OP_DELEGRETURN", |
1433 | .op_rsize_bop = nfsd4_only_status_rsize, | 1466 | .op_rsize_bop = nfsd4_only_status_rsize, |
1467 | .op_get_currentstateid = (stateid_getter)nfsd4_get_delegreturnstateid, | ||
1434 | }, | 1468 | }, |
1435 | [OP_GETATTR] = { | 1469 | [OP_GETATTR] = { |
1436 | .op_func = (nfsd4op_func)nfsd4_getattr, | 1470 | .op_func = (nfsd4op_func)nfsd4_getattr, |
@@ -1453,6 +1487,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1453 | .op_flags = OP_MODIFIES_SOMETHING, | 1487 | .op_flags = OP_MODIFIES_SOMETHING, |
1454 | .op_name = "OP_LOCK", | 1488 | .op_name = "OP_LOCK", |
1455 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize, | 1489 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize, |
1490 | .op_set_currentstateid = (stateid_setter)nfsd4_set_lockstateid, | ||
1456 | }, | 1491 | }, |
1457 | [OP_LOCKT] = { | 1492 | [OP_LOCKT] = { |
1458 | .op_func = (nfsd4op_func)nfsd4_lockt, | 1493 | .op_func = (nfsd4op_func)nfsd4_lockt, |
@@ -1463,15 +1498,16 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1463 | .op_flags = OP_MODIFIES_SOMETHING, | 1498 | .op_flags = OP_MODIFIES_SOMETHING, |
1464 | .op_name = "OP_LOCKU", | 1499 | .op_name = "OP_LOCKU", |
1465 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | 1500 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, |
1501 | .op_get_currentstateid = (stateid_getter)nfsd4_get_lockustateid, | ||
1466 | }, | 1502 | }, |
1467 | [OP_LOOKUP] = { | 1503 | [OP_LOOKUP] = { |
1468 | .op_func = (nfsd4op_func)nfsd4_lookup, | 1504 | .op_func = (nfsd4op_func)nfsd4_lookup, |
1469 | .op_flags = OP_HANDLES_WRONGSEC, | 1505 | .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID, |
1470 | .op_name = "OP_LOOKUP", | 1506 | .op_name = "OP_LOOKUP", |
1471 | }, | 1507 | }, |
1472 | [OP_LOOKUPP] = { | 1508 | [OP_LOOKUPP] = { |
1473 | .op_func = (nfsd4op_func)nfsd4_lookupp, | 1509 | .op_func = (nfsd4op_func)nfsd4_lookupp, |
1474 | .op_flags = OP_HANDLES_WRONGSEC, | 1510 | .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID, |
1475 | .op_name = "OP_LOOKUPP", | 1511 | .op_name = "OP_LOOKUPP", |
1476 | }, | 1512 | }, |
1477 | [OP_NVERIFY] = { | 1513 | [OP_NVERIFY] = { |
@@ -1483,6 +1519,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1483 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, | 1519 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1484 | .op_name = "OP_OPEN", | 1520 | .op_name = "OP_OPEN", |
1485 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize, | 1521 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize, |
1522 | .op_set_currentstateid = (stateid_setter)nfsd4_set_openstateid, | ||
1486 | }, | 1523 | }, |
1487 | [OP_OPEN_CONFIRM] = { | 1524 | [OP_OPEN_CONFIRM] = { |
1488 | .op_func = (nfsd4op_func)nfsd4_open_confirm, | 1525 | .op_func = (nfsd4op_func)nfsd4_open_confirm, |
@@ -1495,25 +1532,30 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1495 | .op_flags = OP_MODIFIES_SOMETHING, | 1532 | .op_flags = OP_MODIFIES_SOMETHING, |
1496 | .op_name = "OP_OPEN_DOWNGRADE", | 1533 | .op_name = "OP_OPEN_DOWNGRADE", |
1497 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | 1534 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, |
1535 | .op_get_currentstateid = (stateid_getter)nfsd4_get_opendowngradestateid, | ||
1536 | .op_set_currentstateid = (stateid_setter)nfsd4_set_opendowngradestateid, | ||
1498 | }, | 1537 | }, |
1499 | [OP_PUTFH] = { | 1538 | [OP_PUTFH] = { |
1500 | .op_func = (nfsd4op_func)nfsd4_putfh, | 1539 | .op_func = (nfsd4op_func)nfsd4_putfh, |
1501 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1540 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1502 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, | 1541 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING |
1542 | | OP_CLEAR_STATEID, | ||
1503 | .op_name = "OP_PUTFH", | 1543 | .op_name = "OP_PUTFH", |
1504 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1544 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1505 | }, | 1545 | }, |
1506 | [OP_PUTPUBFH] = { | 1546 | [OP_PUTPUBFH] = { |
1507 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1547 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1508 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1548 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1509 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, | 1549 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING |
1550 | | OP_CLEAR_STATEID, | ||
1510 | .op_name = "OP_PUTPUBFH", | 1551 | .op_name = "OP_PUTPUBFH", |
1511 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1552 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1512 | }, | 1553 | }, |
1513 | [OP_PUTROOTFH] = { | 1554 | [OP_PUTROOTFH] = { |
1514 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1555 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1515 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1556 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1516 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, | 1557 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING |
1558 | | OP_CLEAR_STATEID, | ||
1517 | .op_name = "OP_PUTROOTFH", | 1559 | .op_name = "OP_PUTROOTFH", |
1518 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1560 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1519 | }, | 1561 | }, |
@@ -1522,6 +1564,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1522 | .op_flags = OP_MODIFIES_SOMETHING, | 1564 | .op_flags = OP_MODIFIES_SOMETHING, |
1523 | .op_name = "OP_READ", | 1565 | .op_name = "OP_READ", |
1524 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize, | 1566 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize, |
1567 | .op_get_currentstateid = (stateid_getter)nfsd4_get_readstateid, | ||
1525 | }, | 1568 | }, |
1526 | [OP_READDIR] = { | 1569 | [OP_READDIR] = { |
1527 | .op_func = (nfsd4op_func)nfsd4_readdir, | 1570 | .op_func = (nfsd4op_func)nfsd4_readdir, |
@@ -1576,6 +1619,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1576 | .op_name = "OP_SETATTR", | 1619 | .op_name = "OP_SETATTR", |
1577 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | 1620 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1578 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize, | 1621 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize, |
1622 | .op_get_currentstateid = (stateid_getter)nfsd4_get_setattrstateid, | ||
1579 | }, | 1623 | }, |
1580 | [OP_SETCLIENTID] = { | 1624 | [OP_SETCLIENTID] = { |
1581 | .op_func = (nfsd4op_func)nfsd4_setclientid, | 1625 | .op_func = (nfsd4op_func)nfsd4_setclientid, |
@@ -1600,6 +1644,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1600 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | 1644 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1601 | .op_name = "OP_WRITE", | 1645 | .op_name = "OP_WRITE", |
1602 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize, | 1646 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize, |
1647 | .op_get_currentstateid = (stateid_getter)nfsd4_get_writestateid, | ||
1603 | }, | 1648 | }, |
1604 | [OP_RELEASE_LOCKOWNER] = { | 1649 | [OP_RELEASE_LOCKOWNER] = { |
1605 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, | 1650 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, |
@@ -1674,12 +1719,14 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1674 | }, | 1719 | }, |
1675 | }; | 1720 | }; |
1676 | 1721 | ||
1722 | #ifdef NFSD_DEBUG | ||
1677 | static const char *nfsd4_op_name(unsigned opnum) | 1723 | static const char *nfsd4_op_name(unsigned opnum) |
1678 | { | 1724 | { |
1679 | if (opnum < ARRAY_SIZE(nfsd4_ops)) | 1725 | if (opnum < ARRAY_SIZE(nfsd4_ops)) |
1680 | return nfsd4_ops[opnum].op_name; | 1726 | return nfsd4_ops[opnum].op_name; |
1681 | return "unknown_operation"; | 1727 | return "unknown_operation"; |
1682 | } | 1728 | } |
1729 | #endif | ||
1683 | 1730 | ||
1684 | #define nfsd4_voidres nfsd4_voidargs | 1731 | #define nfsd4_voidres nfsd4_voidargs |
1685 | struct nfsd4_voidargs { int dummy; }; | 1732 | struct nfsd4_voidargs { int dummy; }; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c5cddd659429..a0a2b535b0e0 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -58,11 +58,15 @@ static const stateid_t one_stateid = { | |||
58 | static const stateid_t zero_stateid = { | 58 | static const stateid_t zero_stateid = { |
59 | /* all fields zero */ | 59 | /* all fields zero */ |
60 | }; | 60 | }; |
61 | static const stateid_t currentstateid = { | ||
62 | .si_generation = 1, | ||
63 | }; | ||
61 | 64 | ||
62 | static u64 current_sessionid = 1; | 65 | static u64 current_sessionid = 1; |
63 | 66 | ||
64 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) | 67 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) |
65 | #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) | 68 | #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) |
69 | #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) | ||
66 | 70 | ||
67 | /* forward declarations */ | 71 | /* forward declarations */ |
68 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); | 72 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); |
@@ -91,6 +95,19 @@ nfs4_lock_state(void) | |||
91 | mutex_lock(&client_mutex); | 95 | mutex_lock(&client_mutex); |
92 | } | 96 | } |
93 | 97 | ||
98 | static void free_session(struct kref *); | ||
99 | |||
100 | /* Must be called under the client_lock */ | ||
101 | static void nfsd4_put_session_locked(struct nfsd4_session *ses) | ||
102 | { | ||
103 | kref_put(&ses->se_ref, free_session); | ||
104 | } | ||
105 | |||
106 | static void nfsd4_get_session(struct nfsd4_session *ses) | ||
107 | { | ||
108 | kref_get(&ses->se_ref); | ||
109 | } | ||
110 | |||
94 | void | 111 | void |
95 | nfs4_unlock_state(void) | 112 | nfs4_unlock_state(void) |
96 | { | 113 | { |
@@ -605,12 +622,20 @@ hash_sessionid(struct nfs4_sessionid *sessionid) | |||
605 | return sid->sequence % SESSION_HASH_SIZE; | 622 | return sid->sequence % SESSION_HASH_SIZE; |
606 | } | 623 | } |
607 | 624 | ||
625 | #ifdef NFSD_DEBUG | ||
608 | static inline void | 626 | static inline void |
609 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) | 627 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) |
610 | { | 628 | { |
611 | u32 *ptr = (u32 *)(&sessionid->data[0]); | 629 | u32 *ptr = (u32 *)(&sessionid->data[0]); |
612 | dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); | 630 | dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); |
613 | } | 631 | } |
632 | #else | ||
633 | static inline void | ||
634 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) | ||
635 | { | ||
636 | } | ||
637 | #endif | ||
638 | |||
614 | 639 | ||
615 | static void | 640 | static void |
616 | gen_sessionid(struct nfsd4_session *ses) | 641 | gen_sessionid(struct nfsd4_session *ses) |
@@ -832,11 +857,12 @@ static void nfsd4_del_conns(struct nfsd4_session *s) | |||
832 | spin_unlock(&clp->cl_lock); | 857 | spin_unlock(&clp->cl_lock); |
833 | } | 858 | } |
834 | 859 | ||
835 | void free_session(struct kref *kref) | 860 | static void free_session(struct kref *kref) |
836 | { | 861 | { |
837 | struct nfsd4_session *ses; | 862 | struct nfsd4_session *ses; |
838 | int mem; | 863 | int mem; |
839 | 864 | ||
865 | BUG_ON(!spin_is_locked(&client_lock)); | ||
840 | ses = container_of(kref, struct nfsd4_session, se_ref); | 866 | ses = container_of(kref, struct nfsd4_session, se_ref); |
841 | nfsd4_del_conns(ses); | 867 | nfsd4_del_conns(ses); |
842 | spin_lock(&nfsd_drc_lock); | 868 | spin_lock(&nfsd_drc_lock); |
@@ -847,6 +873,13 @@ void free_session(struct kref *kref) | |||
847 | kfree(ses); | 873 | kfree(ses); |
848 | } | 874 | } |
849 | 875 | ||
876 | void nfsd4_put_session(struct nfsd4_session *ses) | ||
877 | { | ||
878 | spin_lock(&client_lock); | ||
879 | nfsd4_put_session_locked(ses); | ||
880 | spin_unlock(&client_lock); | ||
881 | } | ||
882 | |||
850 | static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) | 883 | static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) |
851 | { | 884 | { |
852 | struct nfsd4_session *new; | 885 | struct nfsd4_session *new; |
@@ -894,7 +927,9 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
894 | status = nfsd4_new_conn_from_crses(rqstp, new); | 927 | status = nfsd4_new_conn_from_crses(rqstp, new); |
895 | /* whoops: benny points out, status is ignored! (err, or bogus) */ | 928 | /* whoops: benny points out, status is ignored! (err, or bogus) */ |
896 | if (status) { | 929 | if (status) { |
930 | spin_lock(&client_lock); | ||
897 | free_session(&new->se_ref); | 931 | free_session(&new->se_ref); |
932 | spin_unlock(&client_lock); | ||
898 | return NULL; | 933 | return NULL; |
899 | } | 934 | } |
900 | if (cses->flags & SESSION4_BACK_CHAN) { | 935 | if (cses->flags & SESSION4_BACK_CHAN) { |
@@ -1006,12 +1041,13 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
1006 | static inline void | 1041 | static inline void |
1007 | free_client(struct nfs4_client *clp) | 1042 | free_client(struct nfs4_client *clp) |
1008 | { | 1043 | { |
1044 | BUG_ON(!spin_is_locked(&client_lock)); | ||
1009 | while (!list_empty(&clp->cl_sessions)) { | 1045 | while (!list_empty(&clp->cl_sessions)) { |
1010 | struct nfsd4_session *ses; | 1046 | struct nfsd4_session *ses; |
1011 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 1047 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, |
1012 | se_perclnt); | 1048 | se_perclnt); |
1013 | list_del(&ses->se_perclnt); | 1049 | list_del(&ses->se_perclnt); |
1014 | nfsd4_put_session(ses); | 1050 | nfsd4_put_session_locked(ses); |
1015 | } | 1051 | } |
1016 | if (clp->cl_cred.cr_group_info) | 1052 | if (clp->cl_cred.cr_group_info) |
1017 | put_group_info(clp->cl_cred.cr_group_info); | 1053 | put_group_info(clp->cl_cred.cr_group_info); |
@@ -1138,12 +1174,12 @@ static void gen_clid(struct nfs4_client *clp) | |||
1138 | 1174 | ||
1139 | static void gen_confirm(struct nfs4_client *clp) | 1175 | static void gen_confirm(struct nfs4_client *clp) |
1140 | { | 1176 | { |
1177 | __be32 verf[2]; | ||
1141 | static u32 i; | 1178 | static u32 i; |
1142 | u32 *p; | ||
1143 | 1179 | ||
1144 | p = (u32 *)clp->cl_confirm.data; | 1180 | verf[0] = (__be32)get_seconds(); |
1145 | *p++ = get_seconds(); | 1181 | verf[1] = (__be32)i++; |
1146 | *p++ = i++; | 1182 | memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); |
1147 | } | 1183 | } |
1148 | 1184 | ||
1149 | static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t) | 1185 | static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t) |
@@ -1180,7 +1216,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1180 | if (princ) { | 1216 | if (princ) { |
1181 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | 1217 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); |
1182 | if (clp->cl_principal == NULL) { | 1218 | if (clp->cl_principal == NULL) { |
1219 | spin_lock(&client_lock); | ||
1183 | free_client(clp); | 1220 | free_client(clp); |
1221 | spin_unlock(&client_lock); | ||
1184 | return NULL; | 1222 | return NULL; |
1185 | } | 1223 | } |
1186 | } | 1224 | } |
@@ -1347,6 +1385,7 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | |||
1347 | slot->sl_opcnt = resp->opcnt; | 1385 | slot->sl_opcnt = resp->opcnt; |
1348 | slot->sl_status = resp->cstate.status; | 1386 | slot->sl_status = resp->cstate.status; |
1349 | 1387 | ||
1388 | slot->sl_flags |= NFSD4_SLOT_INITIALIZED; | ||
1350 | if (nfsd4_not_cached(resp)) { | 1389 | if (nfsd4_not_cached(resp)) { |
1351 | slot->sl_datalen = 0; | 1390 | slot->sl_datalen = 0; |
1352 | return; | 1391 | return; |
@@ -1374,15 +1413,12 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, | |||
1374 | struct nfsd4_op *op; | 1413 | struct nfsd4_op *op; |
1375 | struct nfsd4_slot *slot = resp->cstate.slot; | 1414 | struct nfsd4_slot *slot = resp->cstate.slot; |
1376 | 1415 | ||
1377 | dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__, | ||
1378 | resp->opcnt, resp->cstate.slot->sl_cachethis); | ||
1379 | |||
1380 | /* Encode the replayed sequence operation */ | 1416 | /* Encode the replayed sequence operation */ |
1381 | op = &args->ops[resp->opcnt - 1]; | 1417 | op = &args->ops[resp->opcnt - 1]; |
1382 | nfsd4_encode_operation(resp, op); | 1418 | nfsd4_encode_operation(resp, op); |
1383 | 1419 | ||
1384 | /* Return nfserr_retry_uncached_rep in next operation. */ | 1420 | /* Return nfserr_retry_uncached_rep in next operation. */ |
1385 | if (args->opcnt > 1 && slot->sl_cachethis == 0) { | 1421 | if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { |
1386 | op = &args->ops[resp->opcnt++]; | 1422 | op = &args->ops[resp->opcnt++]; |
1387 | op->status = nfserr_retry_uncached_rep; | 1423 | op->status = nfserr_retry_uncached_rep; |
1388 | nfsd4_encode_operation(resp, op); | 1424 | nfsd4_encode_operation(resp, op); |
@@ -1575,16 +1611,11 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | |||
1575 | else | 1611 | else |
1576 | return nfserr_seq_misordered; | 1612 | return nfserr_seq_misordered; |
1577 | } | 1613 | } |
1578 | /* Normal */ | 1614 | /* Note unsigned 32-bit arithmetic handles wraparound: */ |
1579 | if (likely(seqid == slot_seqid + 1)) | 1615 | if (likely(seqid == slot_seqid + 1)) |
1580 | return nfs_ok; | 1616 | return nfs_ok; |
1581 | /* Replay */ | ||
1582 | if (seqid == slot_seqid) | 1617 | if (seqid == slot_seqid) |
1583 | return nfserr_replay_cache; | 1618 | return nfserr_replay_cache; |
1584 | /* Wraparound */ | ||
1585 | if (seqid == 1 && (slot_seqid + 1) == 0) | ||
1586 | return nfs_ok; | ||
1587 | /* Misordered replay or misordered new request */ | ||
1588 | return nfserr_seq_misordered; | 1619 | return nfserr_seq_misordered; |
1589 | } | 1620 | } |
1590 | 1621 | ||
@@ -1815,9 +1846,10 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1815 | nfsd4_probe_callback_sync(ses->se_client); | 1846 | nfsd4_probe_callback_sync(ses->se_client); |
1816 | nfs4_unlock_state(); | 1847 | nfs4_unlock_state(); |
1817 | 1848 | ||
1849 | spin_lock(&client_lock); | ||
1818 | nfsd4_del_conns(ses); | 1850 | nfsd4_del_conns(ses); |
1819 | 1851 | nfsd4_put_session_locked(ses); | |
1820 | nfsd4_put_session(ses); | 1852 | spin_unlock(&client_lock); |
1821 | status = nfs_ok; | 1853 | status = nfs_ok; |
1822 | out: | 1854 | out: |
1823 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1855 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -1921,8 +1953,12 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1921 | * sr_highest_slotid and the sr_target_slot id to maxslots */ | 1953 | * sr_highest_slotid and the sr_target_slot id to maxslots */ |
1922 | seq->maxslots = session->se_fchannel.maxreqs; | 1954 | seq->maxslots = session->se_fchannel.maxreqs; |
1923 | 1955 | ||
1924 | status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse); | 1956 | status = check_slot_seqid(seq->seqid, slot->sl_seqid, |
1957 | slot->sl_flags & NFSD4_SLOT_INUSE); | ||
1925 | if (status == nfserr_replay_cache) { | 1958 | if (status == nfserr_replay_cache) { |
1959 | status = nfserr_seq_misordered; | ||
1960 | if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) | ||
1961 | goto out; | ||
1926 | cstate->slot = slot; | 1962 | cstate->slot = slot; |
1927 | cstate->session = session; | 1963 | cstate->session = session; |
1928 | /* Return the cached reply status and set cstate->status | 1964 | /* Return the cached reply status and set cstate->status |
@@ -1938,9 +1974,12 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1938 | conn = NULL; | 1974 | conn = NULL; |
1939 | 1975 | ||
1940 | /* Success! bump slot seqid */ | 1976 | /* Success! bump slot seqid */ |
1941 | slot->sl_inuse = true; | ||
1942 | slot->sl_seqid = seq->seqid; | 1977 | slot->sl_seqid = seq->seqid; |
1943 | slot->sl_cachethis = seq->cachethis; | 1978 | slot->sl_flags |= NFSD4_SLOT_INUSE; |
1979 | if (seq->cachethis) | ||
1980 | slot->sl_flags |= NFSD4_SLOT_CACHETHIS; | ||
1981 | else | ||
1982 | slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; | ||
1944 | 1983 | ||
1945 | cstate->slot = slot; | 1984 | cstate->slot = slot; |
1946 | cstate->session = session; | 1985 | cstate->session = session; |
@@ -2633,8 +2672,6 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | |||
2633 | 2672 | ||
2634 | static int share_access_to_flags(u32 share_access) | 2673 | static int share_access_to_flags(u32 share_access) |
2635 | { | 2674 | { |
2636 | share_access &= ~NFS4_SHARE_WANT_MASK; | ||
2637 | |||
2638 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; | 2675 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; |
2639 | } | 2676 | } |
2640 | 2677 | ||
@@ -2776,10 +2813,15 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2776 | 2813 | ||
2777 | 2814 | ||
2778 | static void | 2815 | static void |
2779 | nfs4_set_claim_prev(struct nfsd4_open *open) | 2816 | nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session) |
2780 | { | 2817 | { |
2781 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 2818 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
2782 | open->op_openowner->oo_owner.so_client->cl_firststate = 1; | 2819 | /* |
2820 | * On a 4.1+ client, we don't create a state record for a client | ||
2821 | * until it performs RECLAIM_COMPLETE: | ||
2822 | */ | ||
2823 | if (!has_session) | ||
2824 | open->op_openowner->oo_owner.so_client->cl_firststate = 1; | ||
2783 | } | 2825 | } |
2784 | 2826 | ||
2785 | /* Should we give out recallable state?: */ | 2827 | /* Should we give out recallable state?: */ |
@@ -2855,6 +2897,27 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | |||
2855 | return 0; | 2897 | return 0; |
2856 | } | 2898 | } |
2857 | 2899 | ||
2900 | static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | ||
2901 | { | ||
2902 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
2903 | if (status == -EAGAIN) | ||
2904 | open->op_why_no_deleg = WND4_CONTENTION; | ||
2905 | else { | ||
2906 | open->op_why_no_deleg = WND4_RESOURCE; | ||
2907 | switch (open->op_deleg_want) { | ||
2908 | case NFS4_SHARE_WANT_READ_DELEG: | ||
2909 | case NFS4_SHARE_WANT_WRITE_DELEG: | ||
2910 | case NFS4_SHARE_WANT_ANY_DELEG: | ||
2911 | break; | ||
2912 | case NFS4_SHARE_WANT_CANCEL: | ||
2913 | open->op_why_no_deleg = WND4_CANCELLED; | ||
2914 | break; | ||
2915 | case NFS4_SHARE_WANT_NO_DELEG: | ||
2916 | BUG(); /* not supposed to get here */ | ||
2917 | } | ||
2918 | } | ||
2919 | } | ||
2920 | |||
2858 | /* | 2921 | /* |
2859 | * Attempt to hand out a delegation. | 2922 | * Attempt to hand out a delegation. |
2860 | */ | 2923 | */ |
@@ -2864,7 +2927,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_ | |||
2864 | struct nfs4_delegation *dp; | 2927 | struct nfs4_delegation *dp; |
2865 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); | 2928 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); |
2866 | int cb_up; | 2929 | int cb_up; |
2867 | int status, flag = 0; | 2930 | int status = 0, flag = 0; |
2868 | 2931 | ||
2869 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); | 2932 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); |
2870 | flag = NFS4_OPEN_DELEGATE_NONE; | 2933 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -2905,11 +2968,16 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_ | |||
2905 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", | 2968 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", |
2906 | STATEID_VAL(&dp->dl_stid.sc_stateid)); | 2969 | STATEID_VAL(&dp->dl_stid.sc_stateid)); |
2907 | out: | 2970 | out: |
2908 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS | ||
2909 | && flag == NFS4_OPEN_DELEGATE_NONE | ||
2910 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
2911 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
2912 | open->op_delegate_type = flag; | 2971 | open->op_delegate_type = flag; |
2972 | if (flag == NFS4_OPEN_DELEGATE_NONE) { | ||
2973 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && | ||
2974 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
2975 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
2976 | |||
2977 | /* 4.1 client asking for a delegation? */ | ||
2978 | if (open->op_deleg_want) | ||
2979 | nfsd4_open_deleg_none_ext(open, status); | ||
2980 | } | ||
2913 | return; | 2981 | return; |
2914 | out_free: | 2982 | out_free: |
2915 | nfs4_put_delegation(dp); | 2983 | nfs4_put_delegation(dp); |
@@ -2918,6 +2986,24 @@ out_no_deleg: | |||
2918 | goto out; | 2986 | goto out; |
2919 | } | 2987 | } |
2920 | 2988 | ||
2989 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, | ||
2990 | struct nfs4_delegation *dp) | ||
2991 | { | ||
2992 | if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && | ||
2993 | dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { | ||
2994 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
2995 | open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; | ||
2996 | } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && | ||
2997 | dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { | ||
2998 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
2999 | open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; | ||
3000 | } | ||
3001 | /* Otherwise the client must be confused wanting a delegation | ||
3002 | * it already has, therefore we don't return | ||
3003 | * NFS4_OPEN_DELEGATE_NONE_EXT and reason. | ||
3004 | */ | ||
3005 | } | ||
3006 | |||
2921 | /* | 3007 | /* |
2922 | * called with nfs4_lock_state() held. | 3008 | * called with nfs4_lock_state() held. |
2923 | */ | 3009 | */ |
@@ -2979,24 +3065,36 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2979 | update_stateid(&stp->st_stid.sc_stateid); | 3065 | update_stateid(&stp->st_stid.sc_stateid); |
2980 | memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3066 | memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
2981 | 3067 | ||
2982 | if (nfsd4_has_session(&resp->cstate)) | 3068 | if (nfsd4_has_session(&resp->cstate)) { |
2983 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 3069 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
2984 | 3070 | ||
3071 | if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { | ||
3072 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
3073 | open->op_why_no_deleg = WND4_NOT_WANTED; | ||
3074 | goto nodeleg; | ||
3075 | } | ||
3076 | } | ||
3077 | |||
2985 | /* | 3078 | /* |
2986 | * Attempt to hand out a delegation. No error return, because the | 3079 | * Attempt to hand out a delegation. No error return, because the |
2987 | * OPEN succeeds even if we fail. | 3080 | * OPEN succeeds even if we fail. |
2988 | */ | 3081 | */ |
2989 | nfs4_open_delegation(current_fh, open, stp); | 3082 | nfs4_open_delegation(current_fh, open, stp); |
2990 | 3083 | nodeleg: | |
2991 | status = nfs_ok; | 3084 | status = nfs_ok; |
2992 | 3085 | ||
2993 | dprintk("%s: stateid=" STATEID_FMT "\n", __func__, | 3086 | dprintk("%s: stateid=" STATEID_FMT "\n", __func__, |
2994 | STATEID_VAL(&stp->st_stid.sc_stateid)); | 3087 | STATEID_VAL(&stp->st_stid.sc_stateid)); |
2995 | out: | 3088 | out: |
3089 | /* 4.1 client trying to upgrade/downgrade delegation? */ | ||
3090 | if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && | ||
3091 | open->op_deleg_want) | ||
3092 | nfsd4_deleg_xgrade_none_ext(open, dp); | ||
3093 | |||
2996 | if (fp) | 3094 | if (fp) |
2997 | put_nfs4_file(fp); | 3095 | put_nfs4_file(fp); |
2998 | if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | 3096 | if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) |
2999 | nfs4_set_claim_prev(open); | 3097 | nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate)); |
3000 | /* | 3098 | /* |
3001 | * To finish the open response, we just need to set the rflags. | 3099 | * To finish the open response, we just need to set the rflags. |
3002 | */ | 3100 | */ |
@@ -3400,7 +3498,14 @@ __be32 | |||
3400 | nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3498 | nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3401 | struct nfsd4_test_stateid *test_stateid) | 3499 | struct nfsd4_test_stateid *test_stateid) |
3402 | { | 3500 | { |
3403 | /* real work is done during encoding */ | 3501 | struct nfsd4_test_stateid_id *stateid; |
3502 | struct nfs4_client *cl = cstate->session->se_client; | ||
3503 | |||
3504 | nfs4_lock_state(); | ||
3505 | list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) | ||
3506 | stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid); | ||
3507 | nfs4_unlock_state(); | ||
3508 | |||
3404 | return nfs_ok; | 3509 | return nfs_ok; |
3405 | } | 3510 | } |
3406 | 3511 | ||
@@ -3596,7 +3701,9 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3596 | cstate->current_fh.fh_dentry->d_name.name); | 3701 | cstate->current_fh.fh_dentry->d_name.name); |
3597 | 3702 | ||
3598 | /* We don't yet support WANT bits: */ | 3703 | /* We don't yet support WANT bits: */ |
3599 | od->od_share_access &= NFS4_SHARE_ACCESS_MASK; | 3704 | if (od->od_deleg_want) |
3705 | dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, | ||
3706 | od->od_deleg_want); | ||
3600 | 3707 | ||
3601 | nfs4_lock_state(); | 3708 | nfs4_lock_state(); |
3602 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, | 3709 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, |
@@ -4353,7 +4460,9 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) | |||
4353 | struct nfs4_client *clp; | 4460 | struct nfs4_client *clp; |
4354 | 4461 | ||
4355 | clp = find_confirmed_client_by_str(name, strhashval); | 4462 | clp = find_confirmed_client_by_str(name, strhashval); |
4356 | return clp ? 1 : 0; | 4463 | if (!clp) |
4464 | return 0; | ||
4465 | return clp->cl_firststate; | ||
4357 | } | 4466 | } |
4358 | 4467 | ||
4359 | /* | 4468 | /* |
@@ -4613,21 +4722,26 @@ set_max_delegations(void) | |||
4613 | 4722 | ||
4614 | /* initialization to perform when the nfsd service is started: */ | 4723 | /* initialization to perform when the nfsd service is started: */ |
4615 | 4724 | ||
4616 | static int | 4725 | int |
4617 | __nfs4_state_start(void) | 4726 | nfs4_state_start(void) |
4618 | { | 4727 | { |
4619 | int ret; | 4728 | int ret; |
4620 | 4729 | ||
4730 | nfsd4_load_reboot_recovery_data(); | ||
4621 | boot_time = get_seconds(); | 4731 | boot_time = get_seconds(); |
4622 | locks_start_grace(&nfsd4_manager); | 4732 | locks_start_grace(&nfsd4_manager); |
4623 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4733 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
4624 | nfsd4_grace); | 4734 | nfsd4_grace); |
4625 | ret = set_callback_cred(); | 4735 | ret = set_callback_cred(); |
4626 | if (ret) | 4736 | if (ret) { |
4627 | return -ENOMEM; | 4737 | ret = -ENOMEM; |
4738 | goto out_recovery; | ||
4739 | } | ||
4628 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4740 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4629 | if (laundry_wq == NULL) | 4741 | if (laundry_wq == NULL) { |
4630 | return -ENOMEM; | 4742 | ret = -ENOMEM; |
4743 | goto out_recovery; | ||
4744 | } | ||
4631 | ret = nfsd4_create_callback_queue(); | 4745 | ret = nfsd4_create_callback_queue(); |
4632 | if (ret) | 4746 | if (ret) |
4633 | goto out_free_laundry; | 4747 | goto out_free_laundry; |
@@ -4636,16 +4750,12 @@ __nfs4_state_start(void) | |||
4636 | return 0; | 4750 | return 0; |
4637 | out_free_laundry: | 4751 | out_free_laundry: |
4638 | destroy_workqueue(laundry_wq); | 4752 | destroy_workqueue(laundry_wq); |
4753 | out_recovery: | ||
4754 | nfs4_release_reclaim(); | ||
4755 | nfsd4_shutdown_recdir(); | ||
4639 | return ret; | 4756 | return ret; |
4640 | } | 4757 | } |
4641 | 4758 | ||
4642 | int | ||
4643 | nfs4_state_start(void) | ||
4644 | { | ||
4645 | nfsd4_load_reboot_recovery_data(); | ||
4646 | return __nfs4_state_start(); | ||
4647 | } | ||
4648 | |||
4649 | static void | 4759 | static void |
4650 | __nfs4_state_shutdown(void) | 4760 | __nfs4_state_shutdown(void) |
4651 | { | 4761 | { |
@@ -4691,3 +4801,104 @@ nfs4_state_shutdown(void) | |||
4691 | nfs4_unlock_state(); | 4801 | nfs4_unlock_state(); |
4692 | nfsd4_destroy_callback_queue(); | 4802 | nfsd4_destroy_callback_queue(); |
4693 | } | 4803 | } |
4804 | |||
4805 | static void | ||
4806 | get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) | ||
4807 | { | ||
4808 | if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) | ||
4809 | memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); | ||
4810 | } | ||
4811 | |||
4812 | static void | ||
4813 | put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) | ||
4814 | { | ||
4815 | if (cstate->minorversion) { | ||
4816 | memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); | ||
4817 | SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); | ||
4818 | } | ||
4819 | } | ||
4820 | |||
4821 | void | ||
4822 | clear_current_stateid(struct nfsd4_compound_state *cstate) | ||
4823 | { | ||
4824 | CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); | ||
4825 | } | ||
4826 | |||
4827 | /* | ||
4828 | * functions to set current state id | ||
4829 | */ | ||
4830 | void | ||
4831 | nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) | ||
4832 | { | ||
4833 | put_stateid(cstate, &odp->od_stateid); | ||
4834 | } | ||
4835 | |||
4836 | void | ||
4837 | nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | ||
4838 | { | ||
4839 | put_stateid(cstate, &open->op_stateid); | ||
4840 | } | ||
4841 | |||
4842 | void | ||
4843 | nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) | ||
4844 | { | ||
4845 | put_stateid(cstate, &close->cl_stateid); | ||
4846 | } | ||
4847 | |||
4848 | void | ||
4849 | nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock) | ||
4850 | { | ||
4851 | put_stateid(cstate, &lock->lk_resp_stateid); | ||
4852 | } | ||
4853 | |||
4854 | /* | ||
4855 | * functions to consume current state id | ||
4856 | */ | ||
4857 | |||
4858 | void | ||
4859 | nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) | ||
4860 | { | ||
4861 | get_stateid(cstate, &odp->od_stateid); | ||
4862 | } | ||
4863 | |||
4864 | void | ||
4865 | nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp) | ||
4866 | { | ||
4867 | get_stateid(cstate, &drp->dr_stateid); | ||
4868 | } | ||
4869 | |||
4870 | void | ||
4871 | nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp) | ||
4872 | { | ||
4873 | get_stateid(cstate, &fsp->fr_stateid); | ||
4874 | } | ||
4875 | |||
4876 | void | ||
4877 | nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) | ||
4878 | { | ||
4879 | get_stateid(cstate, &setattr->sa_stateid); | ||
4880 | } | ||
4881 | |||
4882 | void | ||
4883 | nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) | ||
4884 | { | ||
4885 | get_stateid(cstate, &close->cl_stateid); | ||
4886 | } | ||
4887 | |||
4888 | void | ||
4889 | nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku) | ||
4890 | { | ||
4891 | get_stateid(cstate, &locku->lu_stateid); | ||
4892 | } | ||
4893 | |||
4894 | void | ||
4895 | nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read) | ||
4896 | { | ||
4897 | get_stateid(cstate, &read->rd_stateid); | ||
4898 | } | ||
4899 | |||
4900 | void | ||
4901 | nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write) | ||
4902 | { | ||
4903 | get_stateid(cstate, &write->wr_stateid); | ||
4904 | } | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0ec5a1b9700e..bcd8904ab1e3 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -133,22 +133,6 @@ xdr_error: \ | |||
133 | } \ | 133 | } \ |
134 | } while (0) | 134 | } while (0) |
135 | 135 | ||
136 | static void save_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep) | ||
137 | { | ||
138 | savep->p = argp->p; | ||
139 | savep->end = argp->end; | ||
140 | savep->pagelen = argp->pagelen; | ||
141 | savep->pagelist = argp->pagelist; | ||
142 | } | ||
143 | |||
144 | static void restore_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep) | ||
145 | { | ||
146 | argp->p = savep->p; | ||
147 | argp->end = savep->end; | ||
148 | argp->pagelen = savep->pagelen; | ||
149 | argp->pagelist = savep->pagelist; | ||
150 | } | ||
151 | |||
152 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) | 136 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) |
153 | { | 137 | { |
154 | /* We want more bytes than seem to be available. | 138 | /* We want more bytes than seem to be available. |
@@ -638,14 +622,18 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup | |||
638 | DECODE_TAIL; | 622 | DECODE_TAIL; |
639 | } | 623 | } |
640 | 624 | ||
641 | static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *x) | 625 | static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) |
642 | { | 626 | { |
643 | __be32 *p; | 627 | __be32 *p; |
644 | u32 w; | 628 | u32 w; |
645 | 629 | ||
646 | READ_BUF(4); | 630 | READ_BUF(4); |
647 | READ32(w); | 631 | READ32(w); |
648 | *x = w; | 632 | *share_access = w & NFS4_SHARE_ACCESS_MASK; |
633 | *deleg_want = w & NFS4_SHARE_WANT_MASK; | ||
634 | if (deleg_when) | ||
635 | *deleg_when = w & NFS4_SHARE_WHEN_MASK; | ||
636 | |||
649 | switch (w & NFS4_SHARE_ACCESS_MASK) { | 637 | switch (w & NFS4_SHARE_ACCESS_MASK) { |
650 | case NFS4_SHARE_ACCESS_READ: | 638 | case NFS4_SHARE_ACCESS_READ: |
651 | case NFS4_SHARE_ACCESS_WRITE: | 639 | case NFS4_SHARE_ACCESS_WRITE: |
@@ -673,6 +661,9 @@ static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *x) | |||
673 | w &= ~NFS4_SHARE_WANT_MASK; | 661 | w &= ~NFS4_SHARE_WANT_MASK; |
674 | if (!w) | 662 | if (!w) |
675 | return nfs_ok; | 663 | return nfs_ok; |
664 | |||
665 | if (!deleg_when) /* open_downgrade */ | ||
666 | return nfserr_inval; | ||
676 | switch (w) { | 667 | switch (w) { |
677 | case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL: | 668 | case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL: |
678 | case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED: | 669 | case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED: |
@@ -719,6 +710,7 @@ static __be32 | |||
719 | nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | 710 | nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) |
720 | { | 711 | { |
721 | DECODE_HEAD; | 712 | DECODE_HEAD; |
713 | u32 dummy; | ||
722 | 714 | ||
723 | memset(open->op_bmval, 0, sizeof(open->op_bmval)); | 715 | memset(open->op_bmval, 0, sizeof(open->op_bmval)); |
724 | open->op_iattr.ia_valid = 0; | 716 | open->op_iattr.ia_valid = 0; |
@@ -727,7 +719,9 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
727 | /* seqid, share_access, share_deny, clientid, ownerlen */ | 719 | /* seqid, share_access, share_deny, clientid, ownerlen */ |
728 | READ_BUF(4); | 720 | READ_BUF(4); |
729 | READ32(open->op_seqid); | 721 | READ32(open->op_seqid); |
730 | status = nfsd4_decode_share_access(argp, &open->op_share_access); | 722 | /* decode, yet ignore deleg_when until supported */ |
723 | status = nfsd4_decode_share_access(argp, &open->op_share_access, | ||
724 | &open->op_deleg_want, &dummy); | ||
731 | if (status) | 725 | if (status) |
732 | goto xdr_error; | 726 | goto xdr_error; |
733 | status = nfsd4_decode_share_deny(argp, &open->op_share_deny); | 727 | status = nfsd4_decode_share_deny(argp, &open->op_share_deny); |
@@ -755,14 +749,14 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
755 | goto out; | 749 | goto out; |
756 | break; | 750 | break; |
757 | case NFS4_CREATE_EXCLUSIVE: | 751 | case NFS4_CREATE_EXCLUSIVE: |
758 | READ_BUF(8); | 752 | READ_BUF(NFS4_VERIFIER_SIZE); |
759 | COPYMEM(open->op_verf.data, 8); | 753 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); |
760 | break; | 754 | break; |
761 | case NFS4_CREATE_EXCLUSIVE4_1: | 755 | case NFS4_CREATE_EXCLUSIVE4_1: |
762 | if (argp->minorversion < 1) | 756 | if (argp->minorversion < 1) |
763 | goto xdr_error; | 757 | goto xdr_error; |
764 | READ_BUF(8); | 758 | READ_BUF(NFS4_VERIFIER_SIZE); |
765 | COPYMEM(open->op_verf.data, 8); | 759 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); |
766 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 760 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
767 | &open->op_iattr, &open->op_acl); | 761 | &open->op_iattr, &open->op_acl); |
768 | if (status) | 762 | if (status) |
@@ -848,7 +842,8 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d | |||
848 | return status; | 842 | return status; |
849 | READ_BUF(4); | 843 | READ_BUF(4); |
850 | READ32(open_down->od_seqid); | 844 | READ32(open_down->od_seqid); |
851 | status = nfsd4_decode_share_access(argp, &open_down->od_share_access); | 845 | status = nfsd4_decode_share_access(argp, &open_down->od_share_access, |
846 | &open_down->od_deleg_want, NULL); | ||
852 | if (status) | 847 | if (status) |
853 | return status; | 848 | return status; |
854 | status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny); | 849 | status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny); |
@@ -994,8 +989,8 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient | |||
994 | { | 989 | { |
995 | DECODE_HEAD; | 990 | DECODE_HEAD; |
996 | 991 | ||
997 | READ_BUF(8); | 992 | READ_BUF(NFS4_VERIFIER_SIZE); |
998 | COPYMEM(setclientid->se_verf.data, 8); | 993 | COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); |
999 | 994 | ||
1000 | status = nfsd4_decode_opaque(argp, &setclientid->se_name); | 995 | status = nfsd4_decode_opaque(argp, &setclientid->se_name); |
1001 | if (status) | 996 | if (status) |
@@ -1020,9 +1015,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s | |||
1020 | { | 1015 | { |
1021 | DECODE_HEAD; | 1016 | DECODE_HEAD; |
1022 | 1017 | ||
1023 | READ_BUF(8 + sizeof(nfs4_verifier)); | 1018 | READ_BUF(8 + NFS4_VERIFIER_SIZE); |
1024 | COPYMEM(&scd_c->sc_clientid, 8); | 1019 | COPYMEM(&scd_c->sc_clientid, 8); |
1025 | COPYMEM(&scd_c->sc_confirm, sizeof(nfs4_verifier)); | 1020 | COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); |
1026 | 1021 | ||
1027 | DECODE_TAIL; | 1022 | DECODE_TAIL; |
1028 | } | 1023 | } |
@@ -1385,26 +1380,29 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, | |||
1385 | static __be32 | 1380 | static __be32 |
1386 | nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) | 1381 | nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) |
1387 | { | 1382 | { |
1388 | unsigned int nbytes; | ||
1389 | stateid_t si; | ||
1390 | int i; | 1383 | int i; |
1391 | __be32 *p; | 1384 | __be32 *p, status; |
1392 | __be32 status; | 1385 | struct nfsd4_test_stateid_id *stateid; |
1393 | 1386 | ||
1394 | READ_BUF(4); | 1387 | READ_BUF(4); |
1395 | test_stateid->ts_num_ids = ntohl(*p++); | 1388 | test_stateid->ts_num_ids = ntohl(*p++); |
1396 | 1389 | ||
1397 | nbytes = test_stateid->ts_num_ids * sizeof(stateid_t); | 1390 | INIT_LIST_HEAD(&test_stateid->ts_stateid_list); |
1398 | if (nbytes > (u32)((char *)argp->end - (char *)argp->p)) | ||
1399 | goto xdr_error; | ||
1400 | |||
1401 | test_stateid->ts_saved_args = argp; | ||
1402 | save_buf(argp, &test_stateid->ts_savedp); | ||
1403 | 1391 | ||
1404 | for (i = 0; i < test_stateid->ts_num_ids; i++) { | 1392 | for (i = 0; i < test_stateid->ts_num_ids; i++) { |
1405 | status = nfsd4_decode_stateid(argp, &si); | 1393 | stateid = kmalloc(sizeof(struct nfsd4_test_stateid_id), GFP_KERNEL); |
1394 | if (!stateid) { | ||
1395 | status = PTR_ERR(stateid); | ||
1396 | goto out; | ||
1397 | } | ||
1398 | |||
1399 | defer_free(argp, kfree, stateid); | ||
1400 | INIT_LIST_HEAD(&stateid->ts_id_list); | ||
1401 | list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); | ||
1402 | |||
1403 | status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid); | ||
1406 | if (status) | 1404 | if (status) |
1407 | return status; | 1405 | goto out; |
1408 | } | 1406 | } |
1409 | 1407 | ||
1410 | status = 0; | 1408 | status = 0; |
@@ -2661,8 +2659,8 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2661 | __be32 *p; | 2659 | __be32 *p; |
2662 | 2660 | ||
2663 | if (!nfserr) { | 2661 | if (!nfserr) { |
2664 | RESERVE_SPACE(8); | 2662 | RESERVE_SPACE(NFS4_VERIFIER_SIZE); |
2665 | WRITEMEM(commit->co_verf.data, 8); | 2663 | WRITEMEM(commit->co_verf.data, NFS4_VERIFIER_SIZE); |
2666 | ADJUST_ARGS(); | 2664 | ADJUST_ARGS(); |
2667 | } | 2665 | } |
2668 | return nfserr; | 2666 | return nfserr; |
@@ -2851,6 +2849,20 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op | |||
2851 | WRITE32(0); /* XXX: is NULL principal ok? */ | 2849 | WRITE32(0); /* XXX: is NULL principal ok? */ |
2852 | ADJUST_ARGS(); | 2850 | ADJUST_ARGS(); |
2853 | break; | 2851 | break; |
2852 | case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */ | ||
2853 | switch (open->op_why_no_deleg) { | ||
2854 | case WND4_CONTENTION: | ||
2855 | case WND4_RESOURCE: | ||
2856 | RESERVE_SPACE(8); | ||
2857 | WRITE32(open->op_why_no_deleg); | ||
2858 | WRITE32(0); /* deleg signaling not supported yet */ | ||
2859 | break; | ||
2860 | default: | ||
2861 | RESERVE_SPACE(4); | ||
2862 | WRITE32(open->op_why_no_deleg); | ||
2863 | } | ||
2864 | ADJUST_ARGS(); | ||
2865 | break; | ||
2854 | default: | 2866 | default: |
2855 | BUG(); | 2867 | BUG(); |
2856 | } | 2868 | } |
@@ -3008,7 +3020,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3008 | if (resp->xbuf->page_len) | 3020 | if (resp->xbuf->page_len) |
3009 | return nfserr_resource; | 3021 | return nfserr_resource; |
3010 | 3022 | ||
3011 | RESERVE_SPACE(8); /* verifier */ | 3023 | RESERVE_SPACE(NFS4_VERIFIER_SIZE); |
3012 | savep = p; | 3024 | savep = p; |
3013 | 3025 | ||
3014 | /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ | 3026 | /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ |
@@ -3209,9 +3221,9 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n | |||
3209 | __be32 *p; | 3221 | __be32 *p; |
3210 | 3222 | ||
3211 | if (!nfserr) { | 3223 | if (!nfserr) { |
3212 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); | 3224 | RESERVE_SPACE(8 + NFS4_VERIFIER_SIZE); |
3213 | WRITEMEM(&scd->se_clientid, 8); | 3225 | WRITEMEM(&scd->se_clientid, 8); |
3214 | WRITEMEM(&scd->se_confirm, sizeof(nfs4_verifier)); | 3226 | WRITEMEM(&scd->se_confirm, NFS4_VERIFIER_SIZE); |
3215 | ADJUST_ARGS(); | 3227 | ADJUST_ARGS(); |
3216 | } | 3228 | } |
3217 | else if (nfserr == nfserr_clid_inuse) { | 3229 | else if (nfserr == nfserr_clid_inuse) { |
@@ -3232,7 +3244,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3232 | RESERVE_SPACE(16); | 3244 | RESERVE_SPACE(16); |
3233 | WRITE32(write->wr_bytes_written); | 3245 | WRITE32(write->wr_bytes_written); |
3234 | WRITE32(write->wr_how_written); | 3246 | WRITE32(write->wr_how_written); |
3235 | WRITEMEM(write->wr_verifier.data, 8); | 3247 | WRITEMEM(write->wr_verifier.data, NFS4_VERIFIER_SIZE); |
3236 | ADJUST_ARGS(); | 3248 | ADJUST_ARGS(); |
3237 | } | 3249 | } |
3238 | return nfserr; | 3250 | return nfserr; |
@@ -3391,30 +3403,17 @@ __be32 | |||
3391 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr, | 3403 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr, |
3392 | struct nfsd4_test_stateid *test_stateid) | 3404 | struct nfsd4_test_stateid *test_stateid) |
3393 | { | 3405 | { |
3394 | struct nfsd4_compoundargs *argp; | 3406 | struct nfsd4_test_stateid_id *stateid, *next; |
3395 | struct nfs4_client *cl = resp->cstate.session->se_client; | ||
3396 | stateid_t si; | ||
3397 | __be32 *p; | 3407 | __be32 *p; |
3398 | int i; | ||
3399 | int valid; | ||
3400 | |||
3401 | restore_buf(test_stateid->ts_saved_args, &test_stateid->ts_savedp); | ||
3402 | argp = test_stateid->ts_saved_args; | ||
3403 | 3408 | ||
3404 | RESERVE_SPACE(4); | 3409 | RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids)); |
3405 | *p++ = htonl(test_stateid->ts_num_ids); | 3410 | *p++ = htonl(test_stateid->ts_num_ids); |
3406 | resp->p = p; | ||
3407 | 3411 | ||
3408 | nfs4_lock_state(); | 3412 | list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) { |
3409 | for (i = 0; i < test_stateid->ts_num_ids; i++) { | 3413 | *p++ = htonl(stateid->ts_id_status); |
3410 | nfsd4_decode_stateid(argp, &si); | ||
3411 | valid = nfs4_validate_stateid(cl, &si); | ||
3412 | RESERVE_SPACE(4); | ||
3413 | *p++ = htonl(valid); | ||
3414 | resp->p = p; | ||
3415 | } | 3414 | } |
3416 | nfs4_unlock_state(); | ||
3417 | 3415 | ||
3416 | ADJUST_ARGS(); | ||
3418 | return nfserr; | 3417 | return nfserr; |
3419 | } | 3418 | } |
3420 | 3419 | ||
@@ -3532,7 +3531,7 @@ int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) | |||
3532 | if (length > session->se_fchannel.maxresp_sz) | 3531 | if (length > session->se_fchannel.maxresp_sz) |
3533 | return nfserr_rep_too_big; | 3532 | return nfserr_rep_too_big; |
3534 | 3533 | ||
3535 | if (slot->sl_cachethis == 1 && | 3534 | if ((slot->sl_flags & NFSD4_SLOT_CACHETHIS) && |
3536 | length > session->se_fchannel.maxresp_cached) | 3535 | length > session->se_fchannel.maxresp_cached) |
3537 | return nfserr_rep_too_big_to_cache; | 3536 | return nfserr_rep_too_big_to_cache; |
3538 | 3537 | ||
@@ -3656,8 +3655,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3656 | if (nfsd4_has_session(cs)) { | 3655 | if (nfsd4_has_session(cs)) { |
3657 | if (cs->status != nfserr_replay_cache) { | 3656 | if (cs->status != nfserr_replay_cache) { |
3658 | nfsd4_store_cache_entry(resp); | 3657 | nfsd4_store_cache_entry(resp); |
3659 | dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__); | 3658 | cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; |
3660 | cs->slot->sl_inuse = false; | ||
3661 | } | 3659 | } |
3662 | /* Renew the clientid on success and on replay */ | 3660 | /* Renew the clientid on success and on replay */ |
3663 | release_session_client(cs->session); | 3661 | release_session_client(cs->session); |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index fce472f5f39e..28dfad39f0c5 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -307,33 +307,37 @@ static void set_max_drc(void) | |||
307 | dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem); | 307 | dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem); |
308 | } | 308 | } |
309 | 309 | ||
310 | int nfsd_create_serv(void) | 310 | static int nfsd_get_default_max_blksize(void) |
311 | { | 311 | { |
312 | int err = 0; | 312 | struct sysinfo i; |
313 | unsigned long long target; | ||
314 | unsigned long ret; | ||
315 | |||
316 | si_meminfo(&i); | ||
317 | target = (i.totalram - i.totalhigh) << PAGE_SHIFT; | ||
318 | /* | ||
319 | * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig | ||
320 | * machines, but only uses 32K on 128M machines. Bottom out at | ||
321 | * 8K on 32M and smaller. Of course, this is only a default. | ||
322 | */ | ||
323 | target >>= 12; | ||
324 | |||
325 | ret = NFSSVC_MAXBLKSIZE; | ||
326 | while (ret > target && ret >= 8*1024*2) | ||
327 | ret /= 2; | ||
328 | return ret; | ||
329 | } | ||
313 | 330 | ||
331 | int nfsd_create_serv(void) | ||
332 | { | ||
314 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 333 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
315 | if (nfsd_serv) { | 334 | if (nfsd_serv) { |
316 | svc_get(nfsd_serv); | 335 | svc_get(nfsd_serv); |
317 | return 0; | 336 | return 0; |
318 | } | 337 | } |
319 | if (nfsd_max_blksize == 0) { | 338 | if (nfsd_max_blksize == 0) |
320 | /* choose a suitable default */ | 339 | nfsd_max_blksize = nfsd_get_default_max_blksize(); |
321 | struct sysinfo i; | ||
322 | si_meminfo(&i); | ||
323 | /* Aim for 1/4096 of memory per thread | ||
324 | * This gives 1MB on 4Gig machines | ||
325 | * But only uses 32K on 128M machines. | ||
326 | * Bottom out at 8K on 32M and smaller. | ||
327 | * Of course, this is only a default. | ||
328 | */ | ||
329 | nfsd_max_blksize = NFSSVC_MAXBLKSIZE; | ||
330 | i.totalram <<= PAGE_SHIFT - 12; | ||
331 | while (nfsd_max_blksize > i.totalram && | ||
332 | nfsd_max_blksize >= 8*1024*2) | ||
333 | nfsd_max_blksize /= 2; | ||
334 | } | ||
335 | nfsd_reset_versions(); | 340 | nfsd_reset_versions(); |
336 | |||
337 | nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, | 341 | nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
338 | nfsd_last_thread, nfsd, THIS_MODULE); | 342 | nfsd_last_thread, nfsd, THIS_MODULE); |
339 | if (nfsd_serv == NULL) | 343 | if (nfsd_serv == NULL) |
@@ -341,7 +345,7 @@ int nfsd_create_serv(void) | |||
341 | 345 | ||
342 | set_max_drc(); | 346 | set_max_drc(); |
343 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 347 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
344 | return err; | 348 | return 0; |
345 | } | 349 | } |
346 | 350 | ||
347 | int nfsd_nrpools(void) | 351 | int nfsd_nrpools(void) |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index ffb5df1db94f..1e2b582bc9dc 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -128,12 +128,14 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) | |||
128 | (NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE) | 128 | (NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE) |
129 | 129 | ||
130 | struct nfsd4_slot { | 130 | struct nfsd4_slot { |
131 | bool sl_inuse; | ||
132 | bool sl_cachethis; | ||
133 | u16 sl_opcnt; | ||
134 | u32 sl_seqid; | 131 | u32 sl_seqid; |
135 | __be32 sl_status; | 132 | __be32 sl_status; |
136 | u32 sl_datalen; | 133 | u32 sl_datalen; |
134 | u16 sl_opcnt; | ||
135 | #define NFSD4_SLOT_INUSE (1 << 0) | ||
136 | #define NFSD4_SLOT_CACHETHIS (1 << 1) | ||
137 | #define NFSD4_SLOT_INITIALIZED (1 << 2) | ||
138 | u8 sl_flags; | ||
137 | char sl_data[]; | 139 | char sl_data[]; |
138 | }; | 140 | }; |
139 | 141 | ||
@@ -196,18 +198,7 @@ struct nfsd4_session { | |||
196 | struct nfsd4_slot *se_slots[]; /* forward channel slots */ | 198 | struct nfsd4_slot *se_slots[]; /* forward channel slots */ |
197 | }; | 199 | }; |
198 | 200 | ||
199 | static inline void | 201 | extern void nfsd4_put_session(struct nfsd4_session *ses); |
200 | nfsd4_put_session(struct nfsd4_session *ses) | ||
201 | { | ||
202 | extern void free_session(struct kref *kref); | ||
203 | kref_put(&ses->se_ref, free_session); | ||
204 | } | ||
205 | |||
206 | static inline void | ||
207 | nfsd4_get_session(struct nfsd4_session *ses) | ||
208 | { | ||
209 | kref_get(&ses->se_ref); | ||
210 | } | ||
211 | 202 | ||
212 | /* formatted contents of nfs4_sessionid */ | 203 | /* formatted contents of nfs4_sessionid */ |
213 | struct nfsd4_sessionid { | 204 | struct nfsd4_sessionid { |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index edf6d3ed8777..7423d712eb8c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -737,12 +737,13 @@ static int nfsd_open_break_lease(struct inode *inode, int access) | |||
737 | 737 | ||
738 | /* | 738 | /* |
739 | * Open an existing file or directory. | 739 | * Open an existing file or directory. |
740 | * The access argument indicates the type of open (read/write/lock) | 740 | * The may_flags argument indicates the type of open (read/write/lock) |
741 | * and additional flags. | ||
741 | * N.B. After this call fhp needs an fh_put | 742 | * N.B. After this call fhp needs an fh_put |
742 | */ | 743 | */ |
743 | __be32 | 744 | __be32 |
744 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | 745 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, |
745 | int access, struct file **filp) | 746 | int may_flags, struct file **filp) |
746 | { | 747 | { |
747 | struct dentry *dentry; | 748 | struct dentry *dentry; |
748 | struct inode *inode; | 749 | struct inode *inode; |
@@ -757,7 +758,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |||
757 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE | 758 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE |
758 | * in case a chmod has now revoked permission. | 759 | * in case a chmod has now revoked permission. |
759 | */ | 760 | */ |
760 | err = fh_verify(rqstp, fhp, type, access | NFSD_MAY_OWNER_OVERRIDE); | 761 | err = fh_verify(rqstp, fhp, type, may_flags | NFSD_MAY_OWNER_OVERRIDE); |
761 | if (err) | 762 | if (err) |
762 | goto out; | 763 | goto out; |
763 | 764 | ||
@@ -768,7 +769,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |||
768 | * or any access when mandatory locking enabled | 769 | * or any access when mandatory locking enabled |
769 | */ | 770 | */ |
770 | err = nfserr_perm; | 771 | err = nfserr_perm; |
771 | if (IS_APPEND(inode) && (access & NFSD_MAY_WRITE)) | 772 | if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE)) |
772 | goto out; | 773 | goto out; |
773 | /* | 774 | /* |
774 | * We must ignore files (but only files) which might have mandatory | 775 | * We must ignore files (but only files) which might have mandatory |
@@ -781,12 +782,12 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |||
781 | if (!inode->i_fop) | 782 | if (!inode->i_fop) |
782 | goto out; | 783 | goto out; |
783 | 784 | ||
784 | host_err = nfsd_open_break_lease(inode, access); | 785 | host_err = nfsd_open_break_lease(inode, may_flags); |
785 | if (host_err) /* NOMEM or WOULDBLOCK */ | 786 | if (host_err) /* NOMEM or WOULDBLOCK */ |
786 | goto out_nfserr; | 787 | goto out_nfserr; |
787 | 788 | ||
788 | if (access & NFSD_MAY_WRITE) { | 789 | if (may_flags & NFSD_MAY_WRITE) { |
789 | if (access & NFSD_MAY_READ) | 790 | if (may_flags & NFSD_MAY_READ) |
790 | flags = O_RDWR|O_LARGEFILE; | 791 | flags = O_RDWR|O_LARGEFILE; |
791 | else | 792 | else |
792 | flags = O_WRONLY|O_LARGEFILE; | 793 | flags = O_WRONLY|O_LARGEFILE; |
@@ -795,8 +796,15 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |||
795 | flags, current_cred()); | 796 | flags, current_cred()); |
796 | if (IS_ERR(*filp)) | 797 | if (IS_ERR(*filp)) |
797 | host_err = PTR_ERR(*filp); | 798 | host_err = PTR_ERR(*filp); |
798 | else | 799 | else { |
799 | host_err = ima_file_check(*filp, access); | 800 | host_err = ima_file_check(*filp, may_flags); |
801 | |||
802 | if (may_flags & NFSD_MAY_64BIT_COOKIE) | ||
803 | (*filp)->f_mode |= FMODE_64BITHASH; | ||
804 | else | ||
805 | (*filp)->f_mode |= FMODE_32BITHASH; | ||
806 | } | ||
807 | |||
800 | out_nfserr: | 808 | out_nfserr: |
801 | err = nfserrno(host_err); | 809 | err = nfserrno(host_err); |
802 | out: | 810 | out: |
@@ -2020,8 +2028,13 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | |||
2020 | __be32 err; | 2028 | __be32 err; |
2021 | struct file *file; | 2029 | struct file *file; |
2022 | loff_t offset = *offsetp; | 2030 | loff_t offset = *offsetp; |
2031 | int may_flags = NFSD_MAY_READ; | ||
2032 | |||
2033 | /* NFSv2 only supports 32 bit cookies */ | ||
2034 | if (rqstp->rq_vers > 2) | ||
2035 | may_flags |= NFSD_MAY_64BIT_COOKIE; | ||
2023 | 2036 | ||
2024 | err = nfsd_open(rqstp, fhp, S_IFDIR, NFSD_MAY_READ, &file); | 2037 | err = nfsd_open(rqstp, fhp, S_IFDIR, may_flags, &file); |
2025 | if (err) | 2038 | if (err) |
2026 | goto out; | 2039 | goto out; |
2027 | 2040 | ||
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 1dcd238e11a0..ec0611b2b738 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #define NFSD_MAY_BYPASS_GSS 0x400 | 27 | #define NFSD_MAY_BYPASS_GSS 0x400 |
28 | #define NFSD_MAY_READ_IF_EXEC 0x800 | 28 | #define NFSD_MAY_READ_IF_EXEC 0x800 |
29 | 29 | ||
30 | #define NFSD_MAY_64BIT_COOKIE 0x1000 /* 64 bit readdir cookies for >= NFSv3 */ | ||
31 | |||
30 | #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) | 32 | #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) |
31 | #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) | 33 | #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) |
32 | 34 | ||
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 2364747ee97d..1b3501598ab5 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -43,6 +43,13 @@ | |||
43 | #define NFSD4_MAX_TAGLEN 128 | 43 | #define NFSD4_MAX_TAGLEN 128 |
44 | #define XDR_LEN(n) (((n) + 3) & ~3) | 44 | #define XDR_LEN(n) (((n) + 3) & ~3) |
45 | 45 | ||
46 | #define CURRENT_STATE_ID_FLAG (1<<0) | ||
47 | #define SAVED_STATE_ID_FLAG (1<<1) | ||
48 | |||
49 | #define SET_STATE_ID(c, f) ((c)->sid_flags |= (f)) | ||
50 | #define HAS_STATE_ID(c, f) ((c)->sid_flags & (f)) | ||
51 | #define CLEAR_STATE_ID(c, f) ((c)->sid_flags &= ~(f)) | ||
52 | |||
46 | struct nfsd4_compound_state { | 53 | struct nfsd4_compound_state { |
47 | struct svc_fh current_fh; | 54 | struct svc_fh current_fh; |
48 | struct svc_fh save_fh; | 55 | struct svc_fh save_fh; |
@@ -54,6 +61,10 @@ struct nfsd4_compound_state { | |||
54 | size_t iovlen; | 61 | size_t iovlen; |
55 | u32 minorversion; | 62 | u32 minorversion; |
56 | u32 status; | 63 | u32 status; |
64 | stateid_t current_stateid; | ||
65 | stateid_t save_stateid; | ||
66 | /* to indicate current and saved state id presents */ | ||
67 | u32 sid_flags; | ||
57 | }; | 68 | }; |
58 | 69 | ||
59 | static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs) | 70 | static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs) |
@@ -212,16 +223,19 @@ struct nfsd4_open { | |||
212 | struct xdr_netobj op_fname; /* request - everything but CLAIM_PREV */ | 223 | struct xdr_netobj op_fname; /* request - everything but CLAIM_PREV */ |
213 | u32 op_delegate_type; /* request - CLAIM_PREV only */ | 224 | u32 op_delegate_type; /* request - CLAIM_PREV only */ |
214 | stateid_t op_delegate_stateid; /* request - response */ | 225 | stateid_t op_delegate_stateid; /* request - response */ |
226 | u32 op_why_no_deleg; /* response - DELEG_NONE_EXT only */ | ||
215 | u32 op_create; /* request */ | 227 | u32 op_create; /* request */ |
216 | u32 op_createmode; /* request */ | 228 | u32 op_createmode; /* request */ |
217 | u32 op_bmval[3]; /* request */ | 229 | u32 op_bmval[3]; /* request */ |
218 | struct iattr iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */ | 230 | struct iattr iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */ |
219 | nfs4_verifier verf; /* EXCLUSIVE4 */ | 231 | nfs4_verifier op_verf __attribute__((aligned(32))); |
232 | /* EXCLUSIVE4 */ | ||
220 | clientid_t op_clientid; /* request */ | 233 | clientid_t op_clientid; /* request */ |
221 | struct xdr_netobj op_owner; /* request */ | 234 | struct xdr_netobj op_owner; /* request */ |
222 | u32 op_seqid; /* request */ | 235 | u32 op_seqid; /* request */ |
223 | u32 op_share_access; /* request */ | 236 | u32 op_share_access; /* request */ |
224 | u32 op_share_deny; /* request */ | 237 | u32 op_share_deny; /* request */ |
238 | u32 op_deleg_want; /* request */ | ||
225 | stateid_t op_stateid; /* response */ | 239 | stateid_t op_stateid; /* response */ |
226 | u32 op_recall; /* recall */ | 240 | u32 op_recall; /* recall */ |
227 | struct nfsd4_change_info op_cinfo; /* response */ | 241 | struct nfsd4_change_info op_cinfo; /* response */ |
@@ -234,7 +248,6 @@ struct nfsd4_open { | |||
234 | struct nfs4_acl *op_acl; | 248 | struct nfs4_acl *op_acl; |
235 | }; | 249 | }; |
236 | #define op_iattr iattr | 250 | #define op_iattr iattr |
237 | #define op_verf verf | ||
238 | 251 | ||
239 | struct nfsd4_open_confirm { | 252 | struct nfsd4_open_confirm { |
240 | stateid_t oc_req_stateid /* request */; | 253 | stateid_t oc_req_stateid /* request */; |
@@ -245,8 +258,9 @@ struct nfsd4_open_confirm { | |||
245 | struct nfsd4_open_downgrade { | 258 | struct nfsd4_open_downgrade { |
246 | stateid_t od_stateid; | 259 | stateid_t od_stateid; |
247 | u32 od_seqid; | 260 | u32 od_seqid; |
248 | u32 od_share_access; | 261 | u32 od_share_access; /* request */ |
249 | u32 od_share_deny; | 262 | u32 od_deleg_want; /* request */ |
263 | u32 od_share_deny; /* request */ | ||
250 | }; | 264 | }; |
251 | 265 | ||
252 | 266 | ||
@@ -343,10 +357,15 @@ struct nfsd4_saved_compoundargs { | |||
343 | struct page **pagelist; | 357 | struct page **pagelist; |
344 | }; | 358 | }; |
345 | 359 | ||
360 | struct nfsd4_test_stateid_id { | ||
361 | __be32 ts_id_status; | ||
362 | stateid_t ts_id_stateid; | ||
363 | struct list_head ts_id_list; | ||
364 | }; | ||
365 | |||
346 | struct nfsd4_test_stateid { | 366 | struct nfsd4_test_stateid { |
347 | __be32 ts_num_ids; | 367 | __be32 ts_num_ids; |
348 | struct nfsd4_compoundargs *ts_saved_args; | 368 | struct list_head ts_stateid_list; |
349 | struct nfsd4_saved_compoundargs ts_savedp; | ||
350 | }; | 369 | }; |
351 | 370 | ||
352 | struct nfsd4_free_stateid { | 371 | struct nfsd4_free_stateid { |
@@ -503,7 +522,8 @@ static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp) | |||
503 | 522 | ||
504 | static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) | 523 | static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) |
505 | { | 524 | { |
506 | return !resp->cstate.slot->sl_cachethis || nfsd4_is_solo_sequence(resp); | 525 | return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS) |
526 | || nfsd4_is_solo_sequence(resp); | ||
507 | } | 527 | } |
508 | 528 | ||
509 | #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) | 529 | #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) |