aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-16 15:04:02 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-16 15:04:02 -0500
commit449bf8d03c5b94f00cc014ff601c2fe2eebb5a6e (patch)
tree8f17959c0a20d9ca3061d28036855813c775c783 /fs/nfsd
parentffd3c0260aeeb1fd4d36378d2e06e6410661dd0f (diff)
parentaea240f4162d50e0f2d8bd5ea3ba11b5f072add8 (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/Kconfig2
-rw-r--r--fs/nfsd/export.c24
-rw-r--r--fs/nfsd/nfs4state.c26
-rw-r--r--fs/nfsd/nfs4xdr.c132
-rw-r--r--fs/nfsd/nfsfh.c8
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
100config NFSD_FAULT_INJECTION 100config 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
405static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
406{
407 kmem_cache_free(slab, s);
408}
409
405void 410void
406nfs4_put_delegation(struct nfs4_delegation *dp) 411nfs4_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)
610static void free_generic_stateid(struct nfs4_ol_stateid *stp) 615static 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
616static void release_lock_stateid(struct nfs4_ol_stateid *stp) 621static void release_lock_stateid(struct nfs4_ol_stateid *stp)
@@ -668,7 +673,6 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
668static void release_open_stateid(struct nfs4_ol_stateid *stp) 673static 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;
3156out_free: 3164out_free:
3157 unhash_stid(&dp->dl_stid); 3165 remove_stid(&dp->dl_stid);
3158 nfs4_put_delegation(dp); 3166 nfs4_put_delegation(dp);
3159out_no_deleg: 3167out_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 */
5123void 5129void
5124nfs4_state_shutdown_net(struct net *net) 5130nfs4_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
5149void 5157void
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
945nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) 946nfsd4_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
993static __be32 997static __be32
998nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
999{
1000 if (argp->minorversion == 0)
1001 return nfs_ok;
1002 return nfserr_notsupp;
1003}
1004
1005static __be32
994nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) 1006nfsd4_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
1541static 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
1602struct nfsd4_minorversion_ops { 1586static inline bool
1603 nfsd4_dec *decoders; 1587nfsd4_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
1607static 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 */
1609static 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
1613static __be32 1626static __be32
1614nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 1627nfsd4_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 }
607out:
608 return 0; 607 return 0;
609
610out_bad: 608out_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;
613out_negative: 611out_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/*