diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-16 15:04:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-16 15:04:02 -0500 |
commit | 449bf8d03c5b94f00cc014ff601c2fe2eebb5a6e (patch) | |
tree | 8f17959c0a20d9ca3061d28036855813c775c783 /fs/nfsd | |
parent | ffd3c0260aeeb1fd4d36378d2e06e6410661dd0f (diff) | |
parent | aea240f4162d50e0f2d8bd5ea3ba11b5f072add8 (diff) |
Merge branch 'nfsd-next' of git://linux-nfs.org/~bfields/linux
Pull nfsd changes from Bruce Fields:
"This includes miscellaneous bugfixes and cleanup and a performance fix
for write-heavy NFSv4 workloads.
(The most significant nfsd-relevant change this time is actually in
the delegation patches that went through Viro, fixing a long-standing
bug that can cause NFSv4 clients to miss updates made by non-nfs users
of the filesystem. Those enable some followup nfsd patches which I
have queued locally, but those can wait till 3.14)"
* 'nfsd-next' of git://linux-nfs.org/~bfields/linux: (24 commits)
nfsd: export proper maximum file size to the client
nfsd4: improve write performance with better sendspace reservations
svcrpc: remove an unnecessary assignment
sunrpc: comment typo fix
Revert "nfsd: remove_stid can be incorporated into nfs4_put_delegation"
nfsd4: fix discarded security labels on setattr
NFSD: Add support for NFS v4.2 operation checking
nfsd4: nfsd_shutdown_net needs state lock
NFSD: Combine decode operations for v4 and v4.1
nfsd: -EINVAL on invalid anonuid/gid instead of silent failure
nfsd: return better errors to exportfs
nfsd: fh_update should error out in unexpected cases
nfsd4: need to destroy revoked delegations in destroy_client
nfsd: no need to unhash_stid before free
nfsd: remove_stid can be incorporated into nfs4_put_delegation
nfsd: nfs4_open_delegation needs to remove_stid rather than unhash_stid
nfsd: nfs4_free_stid
nfsd: fix Kconfig syntax
sunrpc: trim off EC bytes in GSSAPI v2 unwrap
gss_krb5: document that we ignore sequence number
...
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/Kconfig | 2 | ||||
-rw-r--r-- | fs/nfsd/export.c | 24 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 26 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 132 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 8 |
5 files changed, 115 insertions, 77 deletions
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index dc8f1ef665ce..f994e750e0d1 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig | |||
@@ -95,7 +95,7 @@ config NFSD_V4_SECURITY_LABEL | |||
95 | Smack policies on NFSv4 files, say N. | 95 | Smack policies on NFSv4 files, say N. |
96 | 96 | ||
97 | WARNING: there is still a chance of backwards-incompatible protocol changes. | 97 | WARNING: there is still a chance of backwards-incompatible protocol changes. |
98 | For now we recommend "Y" only for developers and testers." | 98 | For now we recommend "Y" only for developers and testers. |
99 | 99 | ||
100 | config NFSD_FAULT_INJECTION | 100 | config NFSD_FAULT_INJECTION |
101 | bool "NFS server manual fault injection" | 101 | bool "NFS server manual fault injection" |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 5f38ea36e266..8513c598fabf 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -536,16 +536,12 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
536 | if (err) | 536 | if (err) |
537 | goto out3; | 537 | goto out3; |
538 | exp.ex_anon_uid= make_kuid(&init_user_ns, an_int); | 538 | exp.ex_anon_uid= make_kuid(&init_user_ns, an_int); |
539 | if (!uid_valid(exp.ex_anon_uid)) | ||
540 | goto out3; | ||
541 | 539 | ||
542 | /* anon gid */ | 540 | /* anon gid */ |
543 | err = get_int(&mesg, &an_int); | 541 | err = get_int(&mesg, &an_int); |
544 | if (err) | 542 | if (err) |
545 | goto out3; | 543 | goto out3; |
546 | exp.ex_anon_gid= make_kgid(&init_user_ns, an_int); | 544 | exp.ex_anon_gid= make_kgid(&init_user_ns, an_int); |
547 | if (!gid_valid(exp.ex_anon_gid)) | ||
548 | goto out3; | ||
549 | 545 | ||
550 | /* fsid */ | 546 | /* fsid */ |
551 | err = get_int(&mesg, &an_int); | 547 | err = get_int(&mesg, &an_int); |
@@ -583,6 +579,26 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
583 | exp.ex_uuid); | 579 | exp.ex_uuid); |
584 | if (err) | 580 | if (err) |
585 | goto out4; | 581 | goto out4; |
582 | /* | ||
583 | * No point caching this if it would immediately expire. | ||
584 | * Also, this protects exportfs's dummy export from the | ||
585 | * anon_uid/anon_gid checks: | ||
586 | */ | ||
587 | if (exp.h.expiry_time < seconds_since_boot()) | ||
588 | goto out4; | ||
589 | /* | ||
590 | * For some reason exportfs has been passing down an | ||
591 | * invalid (-1) uid & gid on the "dummy" export which it | ||
592 | * uses to test export support. To make sure exportfs | ||
593 | * sees errors from check_export we therefore need to | ||
594 | * delay these checks till after check_export: | ||
595 | */ | ||
596 | err = -EINVAL; | ||
597 | if (!uid_valid(exp.ex_anon_uid)) | ||
598 | goto out4; | ||
599 | if (!gid_valid(exp.ex_anon_gid)) | ||
600 | goto out4; | ||
601 | err = 0; | ||
586 | } | 602 | } |
587 | 603 | ||
588 | expp = svc_export_lookup(&exp); | 604 | expp = svc_export_lookup(&exp); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f36a30a9f2d1..105d6fa7c514 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -402,11 +402,16 @@ static void remove_stid(struct nfs4_stid *s) | |||
402 | idr_remove(stateids, s->sc_stateid.si_opaque.so_id); | 402 | idr_remove(stateids, s->sc_stateid.si_opaque.so_id); |
403 | } | 403 | } |
404 | 404 | ||
405 | static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s) | ||
406 | { | ||
407 | kmem_cache_free(slab, s); | ||
408 | } | ||
409 | |||
405 | void | 410 | void |
406 | nfs4_put_delegation(struct nfs4_delegation *dp) | 411 | nfs4_put_delegation(struct nfs4_delegation *dp) |
407 | { | 412 | { |
408 | if (atomic_dec_and_test(&dp->dl_count)) { | 413 | if (atomic_dec_and_test(&dp->dl_count)) { |
409 | kmem_cache_free(deleg_slab, dp); | 414 | nfs4_free_stid(deleg_slab, &dp->dl_stid); |
410 | num_delegations--; | 415 | num_delegations--; |
411 | } | 416 | } |
412 | } | 417 | } |
@@ -610,7 +615,7 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp) | |||
610 | static void free_generic_stateid(struct nfs4_ol_stateid *stp) | 615 | static void free_generic_stateid(struct nfs4_ol_stateid *stp) |
611 | { | 616 | { |
612 | remove_stid(&stp->st_stid); | 617 | remove_stid(&stp->st_stid); |
613 | kmem_cache_free(stateid_slab, stp); | 618 | nfs4_free_stid(stateid_slab, &stp->st_stid); |
614 | } | 619 | } |
615 | 620 | ||
616 | static void release_lock_stateid(struct nfs4_ol_stateid *stp) | 621 | static void release_lock_stateid(struct nfs4_ol_stateid *stp) |
@@ -668,7 +673,6 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp) | |||
668 | static void release_open_stateid(struct nfs4_ol_stateid *stp) | 673 | static void release_open_stateid(struct nfs4_ol_stateid *stp) |
669 | { | 674 | { |
670 | unhash_open_stateid(stp); | 675 | unhash_open_stateid(stp); |
671 | unhash_stid(&stp->st_stid); | ||
672 | free_generic_stateid(stp); | 676 | free_generic_stateid(stp); |
673 | } | 677 | } |
674 | 678 | ||
@@ -690,7 +694,6 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) | |||
690 | struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; | 694 | struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; |
691 | 695 | ||
692 | if (s) { | 696 | if (s) { |
693 | unhash_stid(&s->st_stid); | ||
694 | free_generic_stateid(s); | 697 | free_generic_stateid(s); |
695 | oo->oo_last_closed_stid = NULL; | 698 | oo->oo_last_closed_stid = NULL; |
696 | } | 699 | } |
@@ -1127,6 +1130,11 @@ destroy_client(struct nfs4_client *clp) | |||
1127 | dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); | 1130 | dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); |
1128 | destroy_delegation(dp); | 1131 | destroy_delegation(dp); |
1129 | } | 1132 | } |
1133 | list_splice_init(&clp->cl_revoked, &reaplist); | ||
1134 | while (!list_empty(&reaplist)) { | ||
1135 | dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); | ||
1136 | destroy_revoked_delegation(dp); | ||
1137 | } | ||
1130 | while (!list_empty(&clp->cl_openowners)) { | 1138 | while (!list_empty(&clp->cl_openowners)) { |
1131 | oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); | 1139 | oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); |
1132 | release_openowner(oo); | 1140 | release_openowner(oo); |
@@ -3154,7 +3162,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3154 | open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; | 3162 | open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; |
3155 | return; | 3163 | return; |
3156 | out_free: | 3164 | out_free: |
3157 | unhash_stid(&dp->dl_stid); | 3165 | remove_stid(&dp->dl_stid); |
3158 | nfs4_put_delegation(dp); | 3166 | nfs4_put_delegation(dp); |
3159 | out_no_deleg: | 3167 | out_no_deleg: |
3160 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; | 3168 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; |
@@ -3995,10 +4003,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3995 | 4003 | ||
3996 | nfsd4_close_open_stateid(stp); | 4004 | nfsd4_close_open_stateid(stp); |
3997 | 4005 | ||
3998 | if (cstate->minorversion) { | 4006 | if (cstate->minorversion) |
3999 | unhash_stid(&stp->st_stid); | ||
4000 | free_generic_stateid(stp); | 4007 | free_generic_stateid(stp); |
4001 | } else | 4008 | else |
4002 | oo->oo_last_closed_stid = stp; | 4009 | oo->oo_last_closed_stid = stp; |
4003 | 4010 | ||
4004 | if (list_empty(&oo->oo_owner.so_stateids)) { | 4011 | if (list_empty(&oo->oo_owner.so_stateids)) { |
@@ -5119,7 +5126,6 @@ out_recovery: | |||
5119 | return ret; | 5126 | return ret; |
5120 | } | 5127 | } |
5121 | 5128 | ||
5122 | /* should be called with the state lock held */ | ||
5123 | void | 5129 | void |
5124 | nfs4_state_shutdown_net(struct net *net) | 5130 | nfs4_state_shutdown_net(struct net *net) |
5125 | { | 5131 | { |
@@ -5130,6 +5136,7 @@ nfs4_state_shutdown_net(struct net *net) | |||
5130 | cancel_delayed_work_sync(&nn->laundromat_work); | 5136 | cancel_delayed_work_sync(&nn->laundromat_work); |
5131 | locks_end_grace(&nn->nfsd4_manager); | 5137 | locks_end_grace(&nn->nfsd4_manager); |
5132 | 5138 | ||
5139 | nfs4_lock_state(); | ||
5133 | INIT_LIST_HEAD(&reaplist); | 5140 | INIT_LIST_HEAD(&reaplist); |
5134 | spin_lock(&recall_lock); | 5141 | spin_lock(&recall_lock); |
5135 | list_for_each_safe(pos, next, &nn->del_recall_lru) { | 5142 | list_for_each_safe(pos, next, &nn->del_recall_lru) { |
@@ -5144,6 +5151,7 @@ nfs4_state_shutdown_net(struct net *net) | |||
5144 | 5151 | ||
5145 | nfsd4_client_tracking_exit(net); | 5152 | nfsd4_client_tracking_exit(net); |
5146 | nfs4_state_destroy_net(net); | 5153 | nfs4_state_destroy_net(net); |
5154 | nfs4_unlock_state(); | ||
5147 | } | 5155 | } |
5148 | 5156 | ||
5149 | void | 5157 | void |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d9454fe5653f..088de1355e93 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -411,6 +411,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
411 | label->data = kzalloc(dummy32 + 1, GFP_KERNEL); | 411 | label->data = kzalloc(dummy32 + 1, GFP_KERNEL); |
412 | if (!label->data) | 412 | if (!label->data) |
413 | return nfserr_jukebox; | 413 | return nfserr_jukebox; |
414 | label->len = dummy32; | ||
414 | defer_free(argp, kfree, label->data); | 415 | defer_free(argp, kfree, label->data); |
415 | memcpy(label->data, buf, dummy32); | 416 | memcpy(label->data, buf, dummy32); |
416 | } | 417 | } |
@@ -945,13 +946,16 @@ static __be32 | |||
945 | nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) | 946 | nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) |
946 | { | 947 | { |
947 | DECODE_HEAD; | 948 | DECODE_HEAD; |
948 | 949 | ||
950 | if (argp->minorversion >= 1) | ||
951 | return nfserr_notsupp; | ||
952 | |||
949 | status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); | 953 | status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); |
950 | if (status) | 954 | if (status) |
951 | return status; | 955 | return status; |
952 | READ_BUF(4); | 956 | READ_BUF(4); |
953 | READ32(open_conf->oc_seqid); | 957 | READ32(open_conf->oc_seqid); |
954 | 958 | ||
955 | DECODE_TAIL; | 959 | DECODE_TAIL; |
956 | } | 960 | } |
957 | 961 | ||
@@ -991,6 +995,14 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) | |||
991 | } | 995 | } |
992 | 996 | ||
993 | static __be32 | 997 | static __be32 |
998 | nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p) | ||
999 | { | ||
1000 | if (argp->minorversion == 0) | ||
1001 | return nfs_ok; | ||
1002 | return nfserr_notsupp; | ||
1003 | } | ||
1004 | |||
1005 | static __be32 | ||
994 | nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) | 1006 | nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) |
995 | { | 1007 | { |
996 | DECODE_HEAD; | 1008 | DECODE_HEAD; |
@@ -1061,6 +1073,9 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) | |||
1061 | { | 1073 | { |
1062 | DECODE_HEAD; | 1074 | DECODE_HEAD; |
1063 | 1075 | ||
1076 | if (argp->minorversion >= 1) | ||
1077 | return nfserr_notsupp; | ||
1078 | |||
1064 | READ_BUF(sizeof(clientid_t)); | 1079 | READ_BUF(sizeof(clientid_t)); |
1065 | COPYMEM(clientid, sizeof(clientid_t)); | 1080 | COPYMEM(clientid, sizeof(clientid_t)); |
1066 | 1081 | ||
@@ -1111,6 +1126,9 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient | |||
1111 | { | 1126 | { |
1112 | DECODE_HEAD; | 1127 | DECODE_HEAD; |
1113 | 1128 | ||
1129 | if (argp->minorversion >= 1) | ||
1130 | return nfserr_notsupp; | ||
1131 | |||
1114 | READ_BUF(NFS4_VERIFIER_SIZE); | 1132 | READ_BUF(NFS4_VERIFIER_SIZE); |
1115 | COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); | 1133 | COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); |
1116 | 1134 | ||
@@ -1137,6 +1155,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s | |||
1137 | { | 1155 | { |
1138 | DECODE_HEAD; | 1156 | DECODE_HEAD; |
1139 | 1157 | ||
1158 | if (argp->minorversion >= 1) | ||
1159 | return nfserr_notsupp; | ||
1160 | |||
1140 | READ_BUF(8 + NFS4_VERIFIER_SIZE); | 1161 | READ_BUF(8 + NFS4_VERIFIER_SIZE); |
1141 | COPYMEM(&scd_c->sc_clientid, 8); | 1162 | COPYMEM(&scd_c->sc_clientid, 8); |
1142 | COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); | 1163 | COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); |
@@ -1220,6 +1241,9 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel | |||
1220 | { | 1241 | { |
1221 | DECODE_HEAD; | 1242 | DECODE_HEAD; |
1222 | 1243 | ||
1244 | if (argp->minorversion >= 1) | ||
1245 | return nfserr_notsupp; | ||
1246 | |||
1223 | READ_BUF(12); | 1247 | READ_BUF(12); |
1224 | COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); | 1248 | COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); |
1225 | READ32(rlockowner->rl_owner.len); | 1249 | READ32(rlockowner->rl_owner.len); |
@@ -1519,7 +1543,7 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
1519 | [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, | 1543 | [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, |
1520 | [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, | 1544 | [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, |
1521 | [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, | 1545 | [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, |
1522 | [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_noop, | 1546 | [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh, |
1523 | [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, | 1547 | [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, |
1524 | [OP_READ] = (nfsd4_dec)nfsd4_decode_read, | 1548 | [OP_READ] = (nfsd4_dec)nfsd4_decode_read, |
1525 | [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, | 1549 | [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, |
@@ -1536,46 +1560,6 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
1536 | [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, | 1560 | [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
1537 | [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, | 1561 | [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, |
1538 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, | 1562 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, |
1539 | }; | ||
1540 | |||
1541 | static nfsd4_dec nfsd41_dec_ops[] = { | ||
1542 | [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, | ||
1543 | [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, | ||
1544 | [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, | ||
1545 | [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, | ||
1546 | [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
1547 | [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, | ||
1548 | [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, | ||
1549 | [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, | ||
1550 | [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, | ||
1551 | [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, | ||
1552 | [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, | ||
1553 | [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, | ||
1554 | [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, | ||
1555 | [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, | ||
1556 | [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, | ||
1557 | [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, | ||
1558 | [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
1559 | [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
1560 | [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, | ||
1561 | [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, | ||
1562 | [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
1563 | [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, | ||
1564 | [OP_READ] = (nfsd4_dec)nfsd4_decode_read, | ||
1565 | [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, | ||
1566 | [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, | ||
1567 | [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, | ||
1568 | [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, | ||
1569 | [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
1570 | [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, | ||
1571 | [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, | ||
1572 | [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, | ||
1573 | [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, | ||
1574 | [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
1575 | [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp, | ||
1576 | [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, | ||
1577 | [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, | ||
1578 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
1579 | 1563 | ||
1580 | /* new operations for NFSv4.1 */ | 1564 | /* new operations for NFSv4.1 */ |
1581 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, | 1565 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, |
@@ -1599,24 +1583,53 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
1599 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, | 1583 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, |
1600 | }; | 1584 | }; |
1601 | 1585 | ||
1602 | struct nfsd4_minorversion_ops { | 1586 | static inline bool |
1603 | nfsd4_dec *decoders; | 1587 | nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) |
1604 | int nops; | 1588 | { |
1605 | }; | 1589 | if (op->opnum < FIRST_NFS4_OP) |
1590 | return false; | ||
1591 | else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP) | ||
1592 | return false; | ||
1593 | else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP) | ||
1594 | return false; | ||
1595 | else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP) | ||
1596 | return false; | ||
1597 | return true; | ||
1598 | } | ||
1606 | 1599 | ||
1607 | static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { | 1600 | /* |
1608 | [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, | 1601 | * Return a rough estimate of the maximum possible reply size. Note the |
1609 | [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | 1602 | * estimate includes rpc headers so is meant to be passed to |
1610 | [2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | 1603 | * svc_reserve, not svc_reserve_auth. |
1611 | }; | 1604 | * |
1605 | * Also note the current compound encoding permits only one operation to | ||
1606 | * use pages beyond the first one, so the maximum possible length is the | ||
1607 | * maximum over these values, not the sum. | ||
1608 | */ | ||
1609 | static int nfsd4_max_reply(u32 opnum) | ||
1610 | { | ||
1611 | switch (opnum) { | ||
1612 | case OP_READLINK: | ||
1613 | case OP_READDIR: | ||
1614 | /* | ||
1615 | * Both of these ops take a single page for data and put | ||
1616 | * the head and tail in another page: | ||
1617 | */ | ||
1618 | return 2 * PAGE_SIZE; | ||
1619 | case OP_READ: | ||
1620 | return INT_MAX; | ||
1621 | default: | ||
1622 | return PAGE_SIZE; | ||
1623 | } | ||
1624 | } | ||
1612 | 1625 | ||
1613 | static __be32 | 1626 | static __be32 |
1614 | nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | 1627 | nfsd4_decode_compound(struct nfsd4_compoundargs *argp) |
1615 | { | 1628 | { |
1616 | DECODE_HEAD; | 1629 | DECODE_HEAD; |
1617 | struct nfsd4_op *op; | 1630 | struct nfsd4_op *op; |
1618 | struct nfsd4_minorversion_ops *ops; | ||
1619 | bool cachethis = false; | 1631 | bool cachethis = false; |
1632 | int max_reply = PAGE_SIZE; | ||
1620 | int i; | 1633 | int i; |
1621 | 1634 | ||
1622 | READ_BUF(4); | 1635 | READ_BUF(4); |
@@ -1640,10 +1653,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1640 | } | 1653 | } |
1641 | } | 1654 | } |
1642 | 1655 | ||
1643 | if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion)) | 1656 | if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION) |
1644 | argp->opcnt = 0; | 1657 | argp->opcnt = 0; |
1645 | 1658 | ||
1646 | ops = &nfsd4_minorversion[argp->minorversion]; | ||
1647 | for (i = 0; i < argp->opcnt; i++) { | 1659 | for (i = 0; i < argp->opcnt; i++) { |
1648 | op = &argp->ops[i]; | 1660 | op = &argp->ops[i]; |
1649 | op->replay = NULL; | 1661 | op->replay = NULL; |
@@ -1651,8 +1663,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1651 | READ_BUF(4); | 1663 | READ_BUF(4); |
1652 | READ32(op->opnum); | 1664 | READ32(op->opnum); |
1653 | 1665 | ||
1654 | if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) | 1666 | if (nfsd4_opnum_in_range(argp, op)) |
1655 | op->status = ops->decoders[op->opnum](argp, &op->u); | 1667 | op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); |
1656 | else { | 1668 | else { |
1657 | op->opnum = OP_ILLEGAL; | 1669 | op->opnum = OP_ILLEGAL; |
1658 | op->status = nfserr_op_illegal; | 1670 | op->status = nfserr_op_illegal; |
@@ -1667,10 +1679,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1667 | * op in the compound wants to be cached: | 1679 | * op in the compound wants to be cached: |
1668 | */ | 1680 | */ |
1669 | cachethis |= nfsd4_cache_this_op(op); | 1681 | cachethis |= nfsd4_cache_this_op(op); |
1682 | |||
1683 | max_reply = max(max_reply, nfsd4_max_reply(op->opnum)); | ||
1670 | } | 1684 | } |
1671 | /* Sessions make the DRC unnecessary: */ | 1685 | /* Sessions make the DRC unnecessary: */ |
1672 | if (argp->minorversion) | 1686 | if (argp->minorversion) |
1673 | cachethis = false; | 1687 | cachethis = false; |
1688 | if (max_reply != INT_MAX) | ||
1689 | svc_reserve(argp->rqstp, max_reply); | ||
1674 | argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; | 1690 | argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; |
1675 | 1691 | ||
1676 | DECODE_TAIL; | 1692 | DECODE_TAIL; |
@@ -2375,7 +2391,7 @@ out_acl: | |||
2375 | if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { | 2391 | if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { |
2376 | if ((buflen -= 8) < 0) | 2392 | if ((buflen -= 8) < 0) |
2377 | goto out_resource; | 2393 | goto out_resource; |
2378 | WRITE64(~(u64)0); | 2394 | WRITE64(exp->ex_path.mnt->mnt_sb->s_maxbytes); |
2379 | } | 2395 | } |
2380 | if (bmval0 & FATTR4_WORD0_MAXLINK) { | 2396 | if (bmval0 & FATTR4_WORD0_MAXLINK) { |
2381 | if ((buflen -= 4) < 0) | 2397 | if ((buflen -= 4) < 0) |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 3d0e15ae6f72..3c37b160dcad 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -598,22 +598,20 @@ fh_update(struct svc_fh *fhp) | |||
598 | _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); | 598 | _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); |
599 | } else { | 599 | } else { |
600 | if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) | 600 | if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) |
601 | goto out; | 601 | return 0; |
602 | 602 | ||
603 | _fh_update(fhp, fhp->fh_export, dentry); | 603 | _fh_update(fhp, fhp->fh_export, dentry); |
604 | if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) | 604 | if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) |
605 | return nfserr_opnotsupp; | 605 | return nfserr_opnotsupp; |
606 | } | 606 | } |
607 | out: | ||
608 | return 0; | 607 | return 0; |
609 | |||
610 | out_bad: | 608 | out_bad: |
611 | printk(KERN_ERR "fh_update: fh not verified!\n"); | 609 | printk(KERN_ERR "fh_update: fh not verified!\n"); |
612 | goto out; | 610 | return nfserr_serverfault; |
613 | out_negative: | 611 | out_negative: |
614 | printk(KERN_ERR "fh_update: %pd2 still negative!\n", | 612 | printk(KERN_ERR "fh_update: %pd2 still negative!\n", |
615 | dentry); | 613 | dentry); |
616 | goto out; | 614 | return nfserr_serverfault; |
617 | } | 615 | } |
618 | 616 | ||
619 | /* | 617 | /* |