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

Commit 41ef7218 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'nfsd-4.7-1' of git://linux-nfs.org/~bfields/linux

Pull nfsd bugfixes from Bruce Fields:
 "Oleg Drokin found and fixed races in the nfsd4 state code that go back
  to the big nfs4_lock_state removal around 3.17 (but that were also
  probably hard to reproduce before client changes in 3.20 allowed the
  client to perform parallel opens).

  Also fix a 4.1 backchannel crash due to rpc multipath changes in 4.6.
  Trond acked the client-side rpc fixes going through my tree"

* tag 'nfsd-4.7-1' of git://linux-nfs.org/~bfields/linux:
  nfsd: Make init_open_stateid() a bit more whole
  nfsd: Extend the mutex holding region around in nfsd4_process_open2()
  nfsd: Always lock state exclusively.
  rpc: share one xps between all backchannels
  nfsd4/rpc: move backchannel create logic into rpc code
  SUNRPC: fix xprt leak on xps allocation failure
  nfsd: Fix NFSD_MDS_PR_KEY on 32-bit by adding ULL postfix
parents 9c514bed 8c7245ab
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -290,7 +290,7 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
	return error;
}

#define NFSD_MDS_PR_KEY		0x0100000000000000
#define NFSD_MDS_PR_KEY		0x0100000000000000ULL

/*
 * We use the client ID as a unique key for the reservations.
+1 −17
Original line number Diff line number Diff line
@@ -710,22 +710,6 @@ static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc
	}
}

static struct rpc_clnt *create_backchannel_client(struct rpc_create_args *args)
{
	struct rpc_xprt *xprt;

	if (args->protocol != XPRT_TRANSPORT_BC_TCP)
		return rpc_create(args);

	xprt = args->bc_xprt->xpt_bc_xprt;
	if (xprt) {
		xprt_get(xprt);
		return rpc_create_xprt(args, xprt);
	}

	return rpc_create(args);
}

static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
{
	int maxtime = max_cb_time(clp->net);
@@ -768,7 +752,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
		args.authflavor = ses->se_cb_sec.flavor;
	}
	/* Create RPC client */
	client = create_backchannel_client(&args);
	client = rpc_create(&args);
	if (IS_ERR(client)) {
		dprintk("NFSD: couldn't create callback client: %ld\n",
			PTR_ERR(client));
+37 −30
Original line number Diff line number Diff line
@@ -3480,12 +3480,17 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
}

static struct nfs4_ol_stateid *
init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
		struct nfsd4_open *open)
init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open)
{

	struct nfs4_openowner *oo = open->op_openowner;
	struct nfs4_ol_stateid *retstp = NULL;
	struct nfs4_ol_stateid *stp;

	stp = open->op_stp;
	/* We are moving these outside of the spinlocks to avoid the warnings */
	mutex_init(&stp->st_mutex);
	mutex_lock(&stp->st_mutex);

	spin_lock(&oo->oo_owner.so_client->cl_lock);
	spin_lock(&fp->fi_lock);
@@ -3493,6 +3498,8 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
	retstp = nfsd4_find_existing_open(fp, open);
	if (retstp)
		goto out_unlock;

	open->op_stp = NULL;
	atomic_inc(&stp->st_stid.sc_count);
	stp->st_stid.sc_type = NFS4_OPEN_STID;
	INIT_LIST_HEAD(&stp->st_locks);
@@ -3502,14 +3509,19 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
	stp->st_access_bmap = 0;
	stp->st_deny_bmap = 0;
	stp->st_openstp = NULL;
	init_rwsem(&stp->st_rwsem);
	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
	list_add(&stp->st_perfile, &fp->fi_stateids);

out_unlock:
	spin_unlock(&fp->fi_lock);
	spin_unlock(&oo->oo_owner.so_client->cl_lock);
	return retstp;
	if (retstp) {
		mutex_lock(&retstp->st_mutex);
		/* To keep mutex tracking happy */
		mutex_unlock(&stp->st_mutex);
		stp = retstp;
	}
	return stp;
}

/*
@@ -4305,7 +4317,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
	struct nfs4_file *fp = NULL;
	struct nfs4_ol_stateid *stp = NULL;
	struct nfs4_ol_stateid *swapstp = NULL;
	struct nfs4_delegation *dp = NULL;
	__be32 status;

@@ -4335,32 +4346,28 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
	 */
	if (stp) {
		/* Stateid was found, this is an OPEN upgrade */
		down_read(&stp->st_rwsem);
		mutex_lock(&stp->st_mutex);
		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
		if (status) {
			up_read(&stp->st_rwsem);
			mutex_unlock(&stp->st_mutex);
			goto out;
		}
	} else {
		stp = open->op_stp;
		open->op_stp = NULL;
		swapstp = init_open_stateid(stp, fp, open);
		if (swapstp) {
			nfs4_put_stid(&stp->st_stid);
			stp = swapstp;
			down_read(&stp->st_rwsem);
		/* stp is returned locked. */
		stp = init_open_stateid(fp, open);
		/* See if we lost the race to some other thread */
		if (stp->st_access_bmap != 0) {
			status = nfs4_upgrade_open(rqstp, fp, current_fh,
						stp, open);
			if (status) {
				up_read(&stp->st_rwsem);
				mutex_unlock(&stp->st_mutex);
				goto out;
			}
			goto upgrade_out;
		}
		down_read(&stp->st_rwsem);
		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
		if (status) {
			up_read(&stp->st_rwsem);
			mutex_unlock(&stp->st_mutex);
			release_open_stateid(stp);
			goto out;
		}
@@ -4372,7 +4379,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
	}
upgrade_out:
	nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
	up_read(&stp->st_rwsem);
	mutex_unlock(&stp->st_mutex);

	if (nfsd4_has_session(&resp->cstate)) {
		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
@@ -4977,12 +4984,12 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
		 * revoked delegations are kept only for free_stateid.
		 */
		return nfserr_bad_stateid;
	down_write(&stp->st_rwsem);
	mutex_lock(&stp->st_mutex);
	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
	if (status == nfs_ok)
		status = nfs4_check_fh(current_fh, &stp->st_stid);
	if (status != nfs_ok)
		up_write(&stp->st_rwsem);
		mutex_unlock(&stp->st_mutex);
	return status;
}

@@ -5030,7 +5037,7 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
		return status;
	oo = openowner(stp->st_stateowner);
	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
		up_write(&stp->st_rwsem);
		mutex_unlock(&stp->st_mutex);
		nfs4_put_stid(&stp->st_stid);
		return nfserr_bad_stateid;
	}
@@ -5062,12 +5069,12 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	oo = openowner(stp->st_stateowner);
	status = nfserr_bad_stateid;
	if (oo->oo_flags & NFS4_OO_CONFIRMED) {
		up_write(&stp->st_rwsem);
		mutex_unlock(&stp->st_mutex);
		goto put_stateid;
	}
	oo->oo_flags |= NFS4_OO_CONFIRMED;
	nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid);
	up_write(&stp->st_rwsem);
	mutex_unlock(&stp->st_mutex);
	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));

@@ -5143,7 +5150,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
	nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid);
	status = nfs_ok;
put_stateid:
	up_write(&stp->st_rwsem);
	mutex_unlock(&stp->st_mutex);
	nfs4_put_stid(&stp->st_stid);
out:
	nfsd4_bump_seqid(cstate, status);
@@ -5196,7 +5203,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	if (status)
		goto out; 
	nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
	up_write(&stp->st_rwsem);
	mutex_unlock(&stp->st_mutex);

	nfsd4_close_open_stateid(stp);

@@ -5422,7 +5429,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
	stp->st_access_bmap = 0;
	stp->st_deny_bmap = open_stp->st_deny_bmap;
	stp->st_openstp = open_stp;
	init_rwsem(&stp->st_rwsem);
	mutex_init(&stp->st_mutex);
	list_add(&stp->st_locks, &open_stp->st_locks);
	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
	spin_lock(&fp->fi_lock);
@@ -5591,7 +5598,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
					&open_stp, nn);
		if (status)
			goto out;
		up_write(&open_stp->st_rwsem);
		mutex_unlock(&open_stp->st_mutex);
		open_sop = openowner(open_stp->st_stateowner);
		status = nfserr_bad_stateid;
		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
@@ -5600,7 +5607,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		status = lookup_or_create_lock_state(cstate, open_stp, lock,
							&lock_stp, &new);
		if (status == nfs_ok)
			down_write(&lock_stp->st_rwsem);
			mutex_lock(&lock_stp->st_mutex);
	} else {
		status = nfs4_preprocess_seqid_op(cstate,
				       lock->lk_old_lock_seqid,
@@ -5704,7 +5711,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		    seqid_mutating_err(ntohl(status)))
			lock_sop->lo_owner.so_seqid++;

		up_write(&lock_stp->st_rwsem);
		mutex_unlock(&lock_stp->st_mutex);

		/*
		 * If this is a new, never-before-used stateid, and we are
@@ -5874,7 +5881,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
fput:
	fput(filp);
put_stateid:
	up_write(&stp->st_rwsem);
	mutex_unlock(&stp->st_mutex);
	nfs4_put_stid(&stp->st_stid);
out:
	nfsd4_bump_seqid(cstate, status);
+1 −1
Original line number Diff line number Diff line
@@ -535,7 +535,7 @@ struct nfs4_ol_stateid {
	unsigned char			st_access_bmap;
	unsigned char			st_deny_bmap;
	struct nfs4_ol_stateid		*st_openstp;
	struct rw_semaphore		st_rwsem;
	struct mutex			st_mutex;
};

static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
+0 −2
Original line number Diff line number Diff line
@@ -137,8 +137,6 @@ struct rpc_create_args {
#define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT	(1UL << 9)

struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
					struct rpc_xprt *xprt);
struct rpc_clnt	*rpc_bind_new_program(struct rpc_clnt *,
				const struct rpc_program *, u32);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
Loading