Commit 449bf8d0 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents ffd3c026 aea240f4
...@@ -95,7 +95,7 @@ config NFSD_V4_SECURITY_LABEL ...@@ -95,7 +95,7 @@ config NFSD_V4_SECURITY_LABEL
Smack policies on NFSv4 files, say N. Smack policies on NFSv4 files, say N.
WARNING: there is still a chance of backwards-incompatible protocol changes. WARNING: there is still a chance of backwards-incompatible protocol changes.
For now we recommend "Y" only for developers and testers." For now we recommend "Y" only for developers and testers.
config NFSD_FAULT_INJECTION config NFSD_FAULT_INJECTION
bool "NFS server manual fault injection" bool "NFS server manual fault injection"
......
...@@ -536,16 +536,12 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -536,16 +536,12 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
if (err) if (err)
goto out3; goto out3;
exp.ex_anon_uid= make_kuid(&init_user_ns, an_int); exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
if (!uid_valid(exp.ex_anon_uid))
goto out3;
/* anon gid */ /* anon gid */
err = get_int(&mesg, &an_int); err = get_int(&mesg, &an_int);
if (err) if (err)
goto out3; goto out3;
exp.ex_anon_gid= make_kgid(&init_user_ns, an_int); exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
if (!gid_valid(exp.ex_anon_gid))
goto out3;
/* fsid */ /* fsid */
err = get_int(&mesg, &an_int); err = get_int(&mesg, &an_int);
...@@ -583,6 +579,26 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -583,6 +579,26 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
exp.ex_uuid); exp.ex_uuid);
if (err) if (err)
goto out4; goto out4;
/*
* No point caching this if it would immediately expire.
* Also, this protects exportfs's dummy export from the
* anon_uid/anon_gid checks:
*/
if (exp.h.expiry_time < seconds_since_boot())
goto out4;
/*
* For some reason exportfs has been passing down an
* invalid (-1) uid & gid on the "dummy" export which it
* uses to test export support. To make sure exportfs
* sees errors from check_export we therefore need to
* delay these checks till after check_export:
*/
err = -EINVAL;
if (!uid_valid(exp.ex_anon_uid))
goto out4;
if (!gid_valid(exp.ex_anon_gid))
goto out4;
err = 0;
} }
expp = svc_export_lookup(&exp); expp = svc_export_lookup(&exp);
......
...@@ -402,11 +402,16 @@ static void remove_stid(struct nfs4_stid *s) ...@@ -402,11 +402,16 @@ static void remove_stid(struct nfs4_stid *s)
idr_remove(stateids, s->sc_stateid.si_opaque.so_id); idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
} }
static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
{
kmem_cache_free(slab, s);
}
void void
nfs4_put_delegation(struct nfs4_delegation *dp) nfs4_put_delegation(struct nfs4_delegation *dp)
{ {
if (atomic_dec_and_test(&dp->dl_count)) { if (atomic_dec_and_test(&dp->dl_count)) {
kmem_cache_free(deleg_slab, dp); nfs4_free_stid(deleg_slab, &dp->dl_stid);
num_delegations--; num_delegations--;
} }
} }
...@@ -610,7 +615,7 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp) ...@@ -610,7 +615,7 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp)
static void free_generic_stateid(struct nfs4_ol_stateid *stp) static void free_generic_stateid(struct nfs4_ol_stateid *stp)
{ {
remove_stid(&stp->st_stid); remove_stid(&stp->st_stid);
kmem_cache_free(stateid_slab, stp); nfs4_free_stid(stateid_slab, &stp->st_stid);
} }
static void release_lock_stateid(struct nfs4_ol_stateid *stp) 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,7 +673,6 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
static void release_open_stateid(struct nfs4_ol_stateid *stp) static void release_open_stateid(struct nfs4_ol_stateid *stp)
{ {
unhash_open_stateid(stp); unhash_open_stateid(stp);
unhash_stid(&stp->st_stid);
free_generic_stateid(stp); free_generic_stateid(stp);
} }
...@@ -690,7 +694,6 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) ...@@ -690,7 +694,6 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
if (s) { if (s) {
unhash_stid(&s->st_stid);
free_generic_stateid(s); free_generic_stateid(s);
oo->oo_last_closed_stid = NULL; oo->oo_last_closed_stid = NULL;
} }
...@@ -1127,6 +1130,11 @@ destroy_client(struct nfs4_client *clp) ...@@ -1127,6 +1130,11 @@ destroy_client(struct nfs4_client *clp)
dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
destroy_delegation(dp); destroy_delegation(dp);
} }
list_splice_init(&clp->cl_revoked, &reaplist);
while (!list_empty(&reaplist)) {
dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
destroy_revoked_delegation(dp);
}
while (!list_empty(&clp->cl_openowners)) { while (!list_empty(&clp->cl_openowners)) {
oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
release_openowner(oo); release_openowner(oo);
...@@ -3154,7 +3162,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, ...@@ -3154,7 +3162,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
return; return;
out_free: out_free:
unhash_stid(&dp->dl_stid); remove_stid(&dp->dl_stid);
nfs4_put_delegation(dp); nfs4_put_delegation(dp);
out_no_deleg: out_no_deleg:
open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
...@@ -3995,10 +4003,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -3995,10 +4003,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfsd4_close_open_stateid(stp); nfsd4_close_open_stateid(stp);
if (cstate->minorversion) { if (cstate->minorversion)
unhash_stid(&stp->st_stid);
free_generic_stateid(stp); free_generic_stateid(stp);
} else else
oo->oo_last_closed_stid = stp; oo->oo_last_closed_stid = stp;
if (list_empty(&oo->oo_owner.so_stateids)) { if (list_empty(&oo->oo_owner.so_stateids)) {
...@@ -5119,7 +5126,6 @@ nfs4_state_start(void) ...@@ -5119,7 +5126,6 @@ nfs4_state_start(void)
return ret; return ret;
} }
/* should be called with the state lock held */
void void
nfs4_state_shutdown_net(struct net *net) nfs4_state_shutdown_net(struct net *net)
{ {
...@@ -5130,6 +5136,7 @@ nfs4_state_shutdown_net(struct net *net) ...@@ -5130,6 +5136,7 @@ nfs4_state_shutdown_net(struct net *net)
cancel_delayed_work_sync(&nn->laundromat_work); cancel_delayed_work_sync(&nn->laundromat_work);
locks_end_grace(&nn->nfsd4_manager); locks_end_grace(&nn->nfsd4_manager);
nfs4_lock_state();
INIT_LIST_HEAD(&reaplist); INIT_LIST_HEAD(&reaplist);
spin_lock(&recall_lock); spin_lock(&recall_lock);
list_for_each_safe(pos, next, &nn->del_recall_lru) { list_for_each_safe(pos, next, &nn->del_recall_lru) {
...@@ -5144,6 +5151,7 @@ nfs4_state_shutdown_net(struct net *net) ...@@ -5144,6 +5151,7 @@ nfs4_state_shutdown_net(struct net *net)
nfsd4_client_tracking_exit(net); nfsd4_client_tracking_exit(net);
nfs4_state_destroy_net(net); nfs4_state_destroy_net(net);
nfs4_unlock_state();
} }
void void
......
...@@ -411,6 +411,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, ...@@ -411,6 +411,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
label->data = kzalloc(dummy32 + 1, GFP_KERNEL); label->data = kzalloc(dummy32 + 1, GFP_KERNEL);
if (!label->data) if (!label->data)
return nfserr_jukebox; return nfserr_jukebox;
label->len = dummy32;
defer_free(argp, kfree, label->data); defer_free(argp, kfree, label->data);
memcpy(label->data, buf, dummy32); memcpy(label->data, buf, dummy32);
} }
...@@ -945,13 +946,16 @@ static __be32 ...@@ -945,13 +946,16 @@ static __be32
nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
{ {
DECODE_HEAD; DECODE_HEAD;
if (argp->minorversion >= 1)
return nfserr_notsupp;
status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
if (status) if (status)
return status; return status;
READ_BUF(4); READ_BUF(4);
READ32(open_conf->oc_seqid); READ32(open_conf->oc_seqid);
DECODE_TAIL; DECODE_TAIL;
} }
...@@ -990,6 +994,14 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) ...@@ -990,6 +994,14 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
DECODE_TAIL; DECODE_TAIL;
} }
static __be32
nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
{
if (argp->minorversion == 0)
return nfs_ok;
return nfserr_notsupp;
}
static __be32 static __be32
nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
{ {
...@@ -1061,6 +1073,9 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) ...@@ -1061,6 +1073,9 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
{ {
DECODE_HEAD; DECODE_HEAD;
if (argp->minorversion >= 1)
return nfserr_notsupp;
READ_BUF(sizeof(clientid_t)); READ_BUF(sizeof(clientid_t));
COPYMEM(clientid, sizeof(clientid_t)); COPYMEM(clientid, sizeof(clientid_t));
...@@ -1111,6 +1126,9 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient ...@@ -1111,6 +1126,9 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
{ {
DECODE_HEAD; DECODE_HEAD;
if (argp->minorversion >= 1)
return nfserr_notsupp;
READ_BUF(NFS4_VERIFIER_SIZE); READ_BUF(NFS4_VERIFIER_SIZE);
COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE);
...@@ -1137,6 +1155,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s ...@@ -1137,6 +1155,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s
{ {
DECODE_HEAD; DECODE_HEAD;
if (argp->minorversion >= 1)
return nfserr_notsupp;
READ_BUF(8 + NFS4_VERIFIER_SIZE); READ_BUF(8 + NFS4_VERIFIER_SIZE);
COPYMEM(&scd_c->sc_clientid, 8); COPYMEM(&scd_c->sc_clientid, 8);
COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE);
...@@ -1220,6 +1241,9 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel ...@@ -1220,6 +1241,9 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel
{ {
DECODE_HEAD; DECODE_HEAD;
if (argp->minorversion >= 1)
return nfserr_notsupp;
READ_BUF(12); READ_BUF(12);
COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t));
READ32(rlockowner->rl_owner.len); READ32(rlockowner->rl_owner.len);
...@@ -1519,7 +1543,7 @@ static nfsd4_dec nfsd4_dec_ops[] = { ...@@ -1519,7 +1543,7 @@ static nfsd4_dec nfsd4_dec_ops[] = {
[OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
[OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
[OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
[OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_noop, [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh,
[OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
[OP_READ] = (nfsd4_dec)nfsd4_decode_read, [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
[OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
...@@ -1536,46 +1560,6 @@ static nfsd4_dec nfsd4_dec_ops[] = { ...@@ -1536,46 +1560,6 @@ static nfsd4_dec nfsd4_dec_ops[] = {
[OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
[OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
[OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
};
static nfsd4_dec nfsd41_dec_ops[] = {
[OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
[OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
[OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
[OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
[OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
[OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
[OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
[OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
[OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
[OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
[OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
[OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
[OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
[OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
[OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
[OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
[OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
[OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
[OP_READ] = (nfsd4_dec)nfsd4_decode_read,
[OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
[OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
[OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
[OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
[OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
[OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
[OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
[OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
[OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp,
[OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
[OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
[OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp,
/* new operations for NFSv4.1 */ /* new operations for NFSv4.1 */
[OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl,
...@@ -1599,24 +1583,53 @@ static nfsd4_dec nfsd41_dec_ops[] = { ...@@ -1599,24 +1583,53 @@ static nfsd4_dec nfsd41_dec_ops[] = {
[OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
}; };
struct nfsd4_minorversion_ops { static inline bool
nfsd4_dec *decoders; nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
int nops; {
}; if (op->opnum < FIRST_NFS4_OP)
return false;
else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP)
return false;
else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP)
return false;
else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP)
return false;
return true;
}
static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { /*
[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, * Return a rough estimate of the maximum possible reply size. Note the
[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, * estimate includes rpc headers so is meant to be passed to
[2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, * svc_reserve, not svc_reserve_auth.
}; *
* Also note the current compound encoding permits only one operation to
* use pages beyond the first one, so the maximum possible length is the
* maximum over these values, not the sum.
*/
static int nfsd4_max_reply(u32 opnum)
{
switch (opnum) {
case OP_READLINK:
case OP_READDIR:
/*
* Both of these ops take a single page for data and put
* the head and tail in another page:
*/
return 2 * PAGE_SIZE;
case OP_READ:
return INT_MAX;
default:
return PAGE_SIZE;
}
}
static __be32 static __be32
nfsd4_decode_compound(struct nfsd4_compoundargs *argp) nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
{ {
DECODE_HEAD; DECODE_HEAD;
struct nfsd4_op *op; struct nfsd4_op *op;
struct nfsd4_minorversion_ops *ops;
bool cachethis = false; bool cachethis = false;
int max_reply = PAGE_SIZE;
int i; int i;
READ_BUF(4); READ_BUF(4);
...@@ -1640,10 +1653,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -1640,10 +1653,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
} }
} }
if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion)) if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
argp->opcnt = 0; argp->opcnt = 0;
ops = &nfsd4_minorversion[argp->minorversion];
for (i = 0; i < argp->opcnt; i++) { for (i = 0; i < argp->opcnt; i++) {
op = &argp->ops[i]; op = &argp->ops[i];
op->replay = NULL; op->replay = NULL;
...@@ -1651,8 +1663,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -1651,8 +1663,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
READ_BUF(4); READ_BUF(4);
READ32(op->opnum); READ32(op->opnum);
if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) if (nfsd4_opnum_in_range(argp, op))
op->status = ops->decoders[op->opnum](argp, &op->u); op->status = nfsd4_dec_ops[op->opnum](argp, &op->u);
else { else {
op->opnum = OP_ILLEGAL; op->opnum = OP_ILLEGAL;
op->status = nfserr_op_illegal; op->status = nfserr_op_illegal;
...@@ -1667,10 +1679,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -1667,10 +1679,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
* op in the compound wants to be cached: * op in the compound wants to be cached:
*/ */
cachethis |= nfsd4_cache_this_op(op); cachethis |= nfsd4_cache_this_op(op);
max_reply = max(max_reply, nfsd4_max_reply(op->opnum));
} }
/* Sessions make the DRC unnecessary: */ /* Sessions make the DRC unnecessary: */
if (argp->minorversion) if (argp->minorversion)
cachethis = false; cachethis = false;
if (max_reply != INT_MAX)
svc_reserve(argp->rqstp, max_reply);
argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
DECODE_TAIL; DECODE_TAIL;
...@@ -2375,7 +2391,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -2375,7 +2391,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
if ((buflen -= 8) < 0) if ((buflen -= 8) < 0)
goto out_resource; goto out_resource;
WRITE64(~(u64)0); WRITE64(exp->ex_path.mnt->mnt_sb->s_maxbytes);
} }
if (bmval0 & FATTR4_WORD0_MAXLINK) { if (bmval0 & FATTR4_WORD0_MAXLINK) {
if ((buflen -= 4) < 0) if ((buflen -= 4) < 0)
......
...@@ -598,22 +598,20 @@ fh_update(struct svc_fh *fhp) ...@@ -598,22 +598,20 @@ fh_update(struct svc_fh *fhp)
_fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
} else { } else {
if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
goto out; return 0;
_fh_update(fhp, fhp->fh_export, dentry); _fh_update(fhp, fhp->fh_export, dentry);
if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID)
return nfserr_opnotsupp; return nfserr_opnotsupp;
} }
out:
return 0; return 0;
out_bad: out_bad:
printk(KERN_ERR "fh_update: fh not verified!\n"); printk(KERN_ERR "fh_update: fh not verified!\n");
goto out; return nfserr_serverfault;
out_negative: out_negative:
printk(KERN_ERR "fh_update: %pd2 still negative!\n", printk(KERN_ERR "fh_update: %pd2 still negative!\n",
dentry); dentry);
goto out; return nfserr_serverfault;
} }
/* /*
......
...@@ -118,6 +118,9 @@ Needs to be updated if more operations are defined in future.*/ ...@@ -118,6 +118,9 @@ Needs to be updated if more operations are defined in future.*/
#define FIRST_NFS4_OP OP_ACCESS #define FIRST_NFS4_OP OP_ACCESS
#define LAST_NFS4_OP OP_RECLAIM_COMPLETE #define LAST_NFS4_OP OP_RECLAIM_COMPLETE
#define LAST_NFS40_OP OP_RELEASE_LOCKOWNER
#define LAST_NFS41_OP OP_RECLAIM_COMPLETE
#define LAST_NFS42_OP OP_RECLAIM_COMPLETE
enum nfsstat4 { enum nfsstat4 {
NFS4_OK = 0, NFS4_OK = 0,
......
...@@ -150,7 +150,6 @@ gss_verify_mic_v2(struct krb5_ctx *ctx, ...@@ -150,7 +150,6 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
struct xdr_netobj cksumobj = {.len = sizeof(cksumdata), struct xdr_netobj cksumobj = {.len = sizeof(cksumdata),
.data = cksumdata}; .data = cksumdata};
s32 now; s32 now;
u64 seqnum;
u8 *ptr = read_token->data; u8 *ptr = read_token->data;
u8 *cksumkey; u8 *cksumkey;
u8 flags; u8 flags;
...@@ -197,9 +196,10 @@ gss_verify_mic_v2(struct krb5_ctx *ctx, ...@@ -197,9 +196,10 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
if (now > ctx->endtime) if (now > ctx->endtime)
return GSS_S_CONTEXT_EXPIRED; return GSS_S_CONTEXT_EXPIRED;
/* do sequencing checks */ /*
* NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
seqnum = be64_to_cpup((__be64 *)ptr + 8); * doesn't want it checked; see page 6 of rfc 2203.
*/
return GSS_S_COMPLETE; return GSS_S_COMPLETE;
} }
......
...@@ -489,7 +489,6 @@ static u32 ...@@ -489,7 +489,6 @@ static u32
gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
{ {
s32 now; s32 now;
u64 seqnum;
u8 *ptr; u8 *ptr;
u8 flags = 0x00; u8 flags = 0x00;
u16 ec, rrc; u16 ec, rrc;
...@@ -525,7 +524,10 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) ...@@ -525,7 +524,10 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
ec = be16_to_cpup((__be16 *)(ptr + 4)); ec = be16_to_cpup((__be16 *)(ptr + 4));
rrc = be16_to_cpup((__be16 *)(ptr + 6)); rrc = be16_to_cpup((__be16 *)(ptr + 6));
seqnum = be64_to_cpup((__be64 *)(ptr + 8)); /*
* NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
* doesn't want it checked; see page 6 of rfc 2203.
*/
if (rrc != 0) if (rrc != 0)
rotate_left(offset + 16, buf, rrc); rotate_left(offset + 16, buf, rrc);
...@@ -574,8 +576,8 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) ...@@ -574,8 +576,8 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip; buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip; buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip;
/* Trim off the checksum blob */ /* Trim off the trailing "extra count" and checksum blob */
xdr_buf_trim(buf, GSS_KRB5_TOK_HDR_LEN + tailskip); xdr_buf_trim(buf, ec + GSS_KRB5_TOK_HDR_LEN + tailskip);
return GSS_S_COMPLETE; return GSS_S_COMPLETE;
} }
......
...@@ -298,7 +298,8 @@ int gssp_accept_sec_context_upcall(struct net *net, ...@@ -298,7 +298,8 @@ int gssp_accept_sec_context_upcall(struct net *net,
if (res.context_handle) { if (res.context_handle) {
data->out_handle = rctxh.exported_context_token; data->out_handle = rctxh.exported_context_token;
data->mech_oid.len = rctxh.mech.len; data->mech_oid.len = rctxh.mech.len;
memcpy(data->mech_oid.data, rctxh.mech.data, if (rctxh.mech.data)
memcpy(data->mech_oid.data, rctxh.mech.data,
data->mech_oid.len); data->mech_oid.len);
client_name = rctxh.src_name.display_name; client_name = rctxh.src_name.display_name;
} }
......
...@@ -559,6 +559,8 @@ static int gssx_enc_cred(struct xdr_stream *xdr, ...@@ -559,6 +559,8 @@ static int gssx_enc_cred(struct xdr_stream *xdr,
/* cred->elements */ /* cred->elements */
err = dummy_enc_credel_array(xdr, &cred->elements); err = dummy_enc_credel_array(xdr, &cred->elements);
if (err)
return err;
/* cred->cred_handle_reference */ /* cred->cred_handle_reference */
err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
...@@ -740,22 +742,20 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req, ...@@ -740,22 +742,20 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
goto done; goto done;
/* arg->context_handle */ /* arg->context_handle */
if (arg->context_handle) { if (arg->context_handle)
err = gssx_enc_ctx(xdr, arg->context_handle); err = gssx_enc_ctx(xdr, arg->context_handle);
if (err) else
goto done;
} else {
err = gssx_enc_bool(xdr, 0); err = gssx_enc_bool(xdr, 0);
} if (err)
goto done;
/* arg->cred_handle */ /* arg->cred_handle */
if (arg->cred_handle) { if (arg->cred_handle)
err = gssx_enc_cred(xdr, arg->cred_handle); err = gssx_enc_cred(xdr, arg->cred_handle);
if (err) else
goto done;
} else {
err = gssx_enc_bool(xdr, 0); err = gssx_enc_bool(xdr, 0);
} if (err)
goto done;
/* arg->input_token */ /* arg->input_token */
err = gssx_enc_in_token(xdr, &arg->input_token); err = gssx_enc_in_token(xdr, &arg->input_token);
...@@ -763,13 +763,12 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req, ...@@ -763,13 +763,12 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
goto done; goto done;
/* arg->input_cb */ /* arg->input_cb */
if (arg->input_cb) { if (arg->input_cb)
err = gssx_enc_cb(xdr, arg->input_cb); err = gssx_enc_cb(xdr, arg->input_cb);
if (err) else
goto done;
} else {
err = gssx_enc_bool(xdr, 0); err = gssx_enc_bool(xdr, 0);
} if (err)
goto done;
err = gssx_enc_bool(xdr, arg->ret_deleg_cred); err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
if (err) if (err)
......
...@@ -1167,8 +1167,8 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, ...@@ -1167,8 +1167,8 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
if (!ud->found_creds) { if (!ud->found_creds) {
/* userspace seem buggy, we should always get at least a /* userspace seem buggy, we should always get at least a
* mapping to nobody */ * mapping to nobody */
dprintk("RPC: No creds found, marking Negative!\n"); dprintk("RPC: No creds found!\n");
set_bit(CACHE_NEGATIVE, &rsci.h.flags); goto out;
} else { } else {
/* steal creds */ /* steal creds */
......
...@@ -1104,8 +1104,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1104,8 +1104,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
rqstp->rq_vers = vers = svc_getnl(argv); /* version number */ rqstp->rq_vers = vers = svc_getnl(argv); /* version number */
rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */ rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */
progp = serv->sv_program;
for (progp = serv->sv_program; progp; progp = progp->pg_next) for (progp = serv->sv_program; progp; progp = progp->pg_next)
if (prog == progp->pg_prog) if (prog == progp->pg_prog)
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment