Commit 1fc576b8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfsd-4.10-2' of git://linux-nfs.org/~bfields/linux

Pull nfsd fixes from Bruce Fields:
 "Three more miscellaneous nfsd bugfixes"

* tag 'nfsd-4.10-2' of git://linux-nfs.org/~bfields/linux:
  svcrpc: fix oops in absence of krb5 module
  nfsd: special case truncates some more
  NFSD: Fix a null reference case in find_or_create_lock_stateid()
parents e4178c75 034dd34f
...@@ -223,10 +223,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, ...@@ -223,10 +223,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
struct nfs4_layout_stateid *ls; struct nfs4_layout_stateid *ls;
struct nfs4_stid *stp; struct nfs4_stid *stp;
stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache); stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache,
nfsd4_free_layout_stateid);
if (!stp) if (!stp)
return NULL; return NULL;
stp->sc_free = nfsd4_free_layout_stateid;
get_nfs4_file(fp); get_nfs4_file(fp);
stp->sc_file = fp; stp->sc_file = fp;
......
...@@ -633,8 +633,8 @@ find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) ...@@ -633,8 +633,8 @@ find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new)
return co; return co;
} }
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
struct kmem_cache *slab) void (*sc_free)(struct nfs4_stid *))
{ {
struct nfs4_stid *stid; struct nfs4_stid *stid;
int new_id; int new_id;
...@@ -650,6 +650,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, ...@@ -650,6 +650,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
idr_preload_end(); idr_preload_end();
if (new_id < 0) if (new_id < 0)
goto out_free; goto out_free;
stid->sc_free = sc_free;
stid->sc_client = cl; stid->sc_client = cl;
stid->sc_stateid.si_opaque.so_id = new_id; stid->sc_stateid.si_opaque.so_id = new_id;
stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
...@@ -675,15 +677,12 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, ...@@ -675,15 +677,12 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
{ {
struct nfs4_stid *stid; struct nfs4_stid *stid;
struct nfs4_ol_stateid *stp;
stid = nfs4_alloc_stid(clp, stateid_slab); stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
if (!stid) if (!stid)
return NULL; return NULL;
stp = openlockstateid(stid); return openlockstateid(stid);
stp->st_stid.sc_free = nfs4_free_ol_stateid;
return stp;
} }
static void nfs4_free_deleg(struct nfs4_stid *stid) static void nfs4_free_deleg(struct nfs4_stid *stid)
...@@ -781,11 +780,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh, ...@@ -781,11 +780,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
goto out_dec; goto out_dec;
if (delegation_blocked(&current_fh->fh_handle)) if (delegation_blocked(&current_fh->fh_handle))
goto out_dec; goto out_dec;
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
if (dp == NULL) if (dp == NULL)
goto out_dec; goto out_dec;
dp->dl_stid.sc_free = nfs4_free_deleg;
/* /*
* delegation seqid's are never incremented. The 4.1 special * delegation seqid's are never incremented. The 4.1 special
* meaning of seqid 0 isn't meaningful, really, but let's avoid * meaning of seqid 0 isn't meaningful, really, but let's avoid
...@@ -5580,7 +5578,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, ...@@ -5580,7 +5578,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
get_nfs4_file(fp); get_nfs4_file(fp);
stp->st_stid.sc_file = fp; stp->st_stid.sc_file = fp;
stp->st_stid.sc_free = nfs4_free_lock_stateid;
stp->st_access_bmap = 0; stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap; stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp; stp->st_openstp = open_stp;
...@@ -5623,7 +5620,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, ...@@ -5623,7 +5620,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
lst = find_lock_stateid(lo, fi); lst = find_lock_stateid(lo, fi);
if (lst == NULL) { if (lst == NULL) {
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
ns = nfs4_alloc_stid(clp, stateid_slab); ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
if (ns == NULL) if (ns == NULL)
return NULL; return NULL;
......
...@@ -603,8 +603,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, ...@@ -603,8 +603,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
stateid_t *stateid, unsigned char typemask, stateid_t *stateid, unsigned char typemask,
struct nfs4_stid **s, struct nfsd_net *nn); struct nfs4_stid **s, struct nfsd_net *nn);
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
struct kmem_cache *slab); void (*sc_free)(struct nfs4_stid *));
void nfs4_unhash_stid(struct nfs4_stid *s); void nfs4_unhash_stid(struct nfs4_stid *s);
void nfs4_put_stid(struct nfs4_stid *s); void nfs4_put_stid(struct nfs4_stid *s);
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
......
...@@ -332,37 +332,6 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) ...@@ -332,37 +332,6 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
} }
} }
static __be32
nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct iattr *iap)
{
struct inode *inode = d_inode(fhp->fh_dentry);
int host_err;
if (iap->ia_size < inode->i_size) {
__be32 err;
err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
if (err)
return err;
}
host_err = get_write_access(inode);
if (host_err)
goto out_nfserrno;
host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
if (host_err)
goto out_put_write_access;
return 0;
out_put_write_access:
put_write_access(inode);
out_nfserrno:
return nfserrno(host_err);
}
/* /*
* Set various file attributes. After this call fhp needs an fh_put. * Set various file attributes. After this call fhp needs an fh_put.
*/ */
...@@ -377,7 +346,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, ...@@ -377,7 +346,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
__be32 err; __be32 err;
int host_err; int host_err;
bool get_write_count; bool get_write_count;
int size_change = 0;
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
...@@ -390,11 +358,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, ...@@ -390,11 +358,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
/* Get inode */ /* Get inode */
err = fh_verify(rqstp, fhp, ftype, accmode); err = fh_verify(rqstp, fhp, ftype, accmode);
if (err) if (err)
goto out; return err;
if (get_write_count) { if (get_write_count) {
host_err = fh_want_write(fhp); host_err = fh_want_write(fhp);
if (host_err) if (host_err)
return nfserrno(host_err); goto out_host_err;
} }
dentry = fhp->fh_dentry; dentry = fhp->fh_dentry;
...@@ -405,50 +373,59 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, ...@@ -405,50 +373,59 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
iap->ia_valid &= ~ATTR_MODE; iap->ia_valid &= ~ATTR_MODE;
if (!iap->ia_valid) if (!iap->ia_valid)
goto out; return 0;
nfsd_sanitize_attrs(inode, iap); nfsd_sanitize_attrs(inode, iap);
if (check_guard && guardtime != inode->i_ctime.tv_sec)
return nfserr_notsync;
/* /*
* The size case is special, it changes the file in addition to the * The size case is special, it changes the file in addition to the
* attributes. * attributes, and file systems don't expect it to be mixed with
* "random" attribute changes. We thus split out the size change
* into a separate call for vfs_truncate, and do the rest as a
* a separate setattr call.
*/ */
if (iap->ia_valid & ATTR_SIZE) { if (iap->ia_valid & ATTR_SIZE) {
err = nfsd_get_write_access(rqstp, fhp, iap); struct path path = {
if (err) .mnt = fhp->fh_export->ex_path.mnt,
goto out; .dentry = dentry,
size_change = 1; };
bool implicit_mtime = false;
/* /*
* RFC5661, Section 18.30.4: * vfs_truncate implicity updates the mtime IFF the file size
* Changing the size of a file with SETATTR indirectly * actually changes. Avoid the additional seattr call below if
* changes the time_modify and change attributes. * the only other attribute that the client sends is the mtime.
*
* (and similar for the older RFCs)
*/ */
if (iap->ia_size != i_size_read(inode)) if (iap->ia_size != i_size_read(inode) &&
iap->ia_valid |= ATTR_MTIME; ((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0))
} implicit_mtime = true;
iap->ia_valid |= ATTR_CTIME; host_err = vfs_truncate(&path, iap->ia_size);
if (host_err)
goto out_host_err;
if (check_guard && guardtime != inode->i_ctime.tv_sec) { iap->ia_valid &= ~ATTR_SIZE;
err = nfserr_notsync; if (implicit_mtime)
goto out_put_write_access; iap->ia_valid &= ~ATTR_MTIME;
if (!iap->ia_valid)
goto done;
} }
iap->ia_valid |= ATTR_CTIME;
fh_lock(fhp); fh_lock(fhp);
host_err = notify_change(dentry, iap, NULL); host_err = notify_change(dentry, iap, NULL);
fh_unlock(fhp); fh_unlock(fhp);
err = nfserrno(host_err); if (host_err)
goto out_host_err;
out_put_write_access: done:
if (size_change) host_err = commit_metadata(fhp);
put_write_access(inode); out_host_err:
if (!err) return nfserrno(host_err);
err = nfserrno(commit_metadata(fhp));
out:
return err;
} }
#if defined(CONFIG_NFSD_V4) #if defined(CONFIG_NFSD_V4)
......
...@@ -260,7 +260,7 @@ static int gssx_dec_option_array(struct xdr_stream *xdr, ...@@ -260,7 +260,7 @@ static int gssx_dec_option_array(struct xdr_stream *xdr,
if (!oa->data) if (!oa->data)
return -ENOMEM; return -ENOMEM;
creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL); creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
if (!creds) { if (!creds) {
kfree(oa->data); kfree(oa->data);
return -ENOMEM; return -ENOMEM;
......
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