Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −2
Original line number Original line Diff line number Diff line
@@ -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;


+8 −11
Original line number Original line Diff line number Diff line
@@ -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,
	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,
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,
		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,
	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,
	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;


+2 −2
Original line number Original line Diff line number Diff line
@@ -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);
+37 −60
Original line number Original line Diff line number Diff line
@@ -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,
	__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,
	/* 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,
		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)
+1 −1
Original line number Original line Diff line number Diff line
@@ -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;