diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 691 | 
1 files changed, 445 insertions, 246 deletions
| diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f0c849c98fe4..e809d2305ebf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -72,18 +72,21 @@  #define NFS4_MAX_LOOP_ON_RECOVER (10) +static unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE; +  struct nfs4_opendata;  static int _nfs4_proc_open(struct nfs4_opendata *data);  static int _nfs4_recover_proc_open(struct nfs4_opendata *data);  static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);  static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); +static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);  static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);  static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,  			    struct nfs_fattr *fattr, struct iattr *sattr,  			    struct nfs4_state *state);  #ifdef CONFIG_NFS_V4_1 -static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *); -static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *); +static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *); +static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);  #endif  /* Prevent leaks of NFSv4 errors into userland */  static int nfs4_map_errors(int err) @@ -193,7 +196,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent  	 * when talking to the server, we always send cookie 0  	 * instead of 1 or 2.  	 */ -	start = p = kmap_atomic(*readdir->pages, KM_USER0); +	start = p = kmap_atomic(*readdir->pages);  	if (cookie == 0) {  		*p++ = xdr_one;                                  /* next */ @@ -221,7 +224,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent  	readdir->pgbase = (char *)p - (char *)start;  	readdir->count -= readdir->pgbase; -	kunmap_atomic(start, KM_USER0); +	kunmap_atomic(start);  }  static int nfs4_wait_clnt_recover(struct nfs_client *clp) @@ -259,15 +262,28 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc  {  	struct nfs_client *clp = server->nfs_client;  	struct nfs4_state *state = exception->state; +	struct inode *inode = exception->inode;  	int ret = errorcode;  	exception->retry = 0;  	switch(errorcode) {  		case 0:  			return 0; +		case -NFS4ERR_OPENMODE: +			if (nfs_have_delegation(inode, FMODE_READ)) { +				nfs_inode_return_delegation(inode); +				exception->retry = 1; +				return 0; +			} +			if (state == NULL) +				break; +			nfs4_schedule_stateid_recovery(server, state); +			goto wait_on_recovery; +		case -NFS4ERR_DELEG_REVOKED:  		case -NFS4ERR_ADMIN_REVOKED:  		case -NFS4ERR_BAD_STATEID: -		case -NFS4ERR_OPENMODE: +			if (state != NULL) +				nfs_remove_bad_delegation(state->inode);  			if (state == NULL)  				break;  			nfs4_schedule_stateid_recovery(server, state); @@ -360,16 +376,14 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp   * When updating highest_used_slotid there may be "holes" in the bitmap   * so we need to scan down from highest_used_slotid to 0 looking for the now   * highest slotid in use. - * If none found, highest_used_slotid is set to -1. + * If none found, highest_used_slotid is set to NFS4_NO_SLOT.   *   * Must be called while holding tbl->slot_tbl_lock   */  static void -nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) +nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid)  { -	int slotid = free_slotid; - -	BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); +	BUG_ON(slotid >= NFS4_MAX_SLOT_TABLE);  	/* clear used bit in bitmap */  	__clear_bit(slotid, tbl->used_slots); @@ -379,10 +393,16 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)  		if (slotid < tbl->max_slots)  			tbl->highest_used_slotid = slotid;  		else -			tbl->highest_used_slotid = -1; +			tbl->highest_used_slotid = NFS4_NO_SLOT;  	} -	dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, -		free_slotid, tbl->highest_used_slotid); +	dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, +		slotid, tbl->highest_used_slotid); +} + +bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) +{ +	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); +	return true;  }  /* @@ -390,16 +410,13 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)   */  static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)  { -	struct rpc_task *task; -  	if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { -		task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); -		if (task) -			rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); +		rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq, +				nfs4_set_task_privileged, NULL);  		return;  	} -	if (ses->fc_slot_table.highest_used_slotid != -1) +	if (ses->fc_slot_table.highest_used_slotid != NFS4_NO_SLOT)  		return;  	dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__); @@ -412,7 +429,7 @@ static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)  void nfs4_check_drain_bc_complete(struct nfs4_session *ses)  {  	if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) || -	    ses->bc_slot_table.highest_used_slotid != -1) +	    ses->bc_slot_table.highest_used_slotid != NFS4_NO_SLOT)  		return;  	dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);  	complete(&ses->bc_slot_table.complete); @@ -507,25 +524,25 @@ static int nfs4_sequence_done(struct rpc_task *task,   * nfs4_find_slot looks for an unset bit in the used_slots bitmap.   * If found, we mark the slot as used, update the highest_used_slotid,   * and respectively set up the sequence operation args. - * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. + * The slot number is returned if found, or NFS4_NO_SLOT otherwise.   *   * Note: must be called with under the slot_tbl_lock.   */ -static u8 +static u32  nfs4_find_slot(struct nfs4_slot_table *tbl)  { -	int slotid; -	u8 ret_id = NFS4_MAX_SLOT_TABLE; -	BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); +	u32 slotid; +	u32 ret_id = NFS4_NO_SLOT; -	dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", +	dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n",  		__func__, tbl->used_slots[0], tbl->highest_used_slotid,  		tbl->max_slots);  	slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots);  	if (slotid >= tbl->max_slots)  		goto out;  	__set_bit(slotid, tbl->used_slots); -	if (slotid > tbl->highest_used_slotid) +	if (slotid > tbl->highest_used_slotid || +			tbl->highest_used_slotid == NFS4_NO_SLOT)  		tbl->highest_used_slotid = slotid;  	ret_id = slotid;  out: @@ -534,15 +551,25 @@ out:  	return ret_id;  } +static void nfs41_init_sequence(struct nfs4_sequence_args *args, +		struct nfs4_sequence_res *res, int cache_reply) +{ +	args->sa_session = NULL; +	args->sa_cache_this = 0; +	if (cache_reply) +		args->sa_cache_this = 1; +	res->sr_session = NULL; +	res->sr_slot = NULL; +} +  int nfs41_setup_sequence(struct nfs4_session *session,  				struct nfs4_sequence_args *args,  				struct nfs4_sequence_res *res, -				int cache_reply,  				struct rpc_task *task)  {  	struct nfs4_slot *slot;  	struct nfs4_slot_table *tbl; -	u8 slotid; +	u32 slotid;  	dprintk("--> %s\n", __func__);  	/* slot already allocated? */ @@ -570,7 +597,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,  	}  	slotid = nfs4_find_slot(tbl); -	if (slotid == NFS4_MAX_SLOT_TABLE) { +	if (slotid == NFS4_NO_SLOT) {  		rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);  		spin_unlock(&tbl->slot_tbl_lock);  		dprintk("<-- %s: no free slots\n", __func__); @@ -582,7 +609,6 @@ int nfs41_setup_sequence(struct nfs4_session *session,  	slot = tbl->slots + slotid;  	args->sa_session = session;  	args->sa_slotid = slotid; -	args->sa_cache_this = cache_reply;  	dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); @@ -602,24 +628,19 @@ EXPORT_SYMBOL_GPL(nfs41_setup_sequence);  int nfs4_setup_sequence(const struct nfs_server *server,  			struct nfs4_sequence_args *args,  			struct nfs4_sequence_res *res, -			int cache_reply,  			struct rpc_task *task)  {  	struct nfs4_session *session = nfs4_get_session(server);  	int ret = 0; -	if (session == NULL) { -		args->sa_session = NULL; -		res->sr_session = NULL; +	if (session == NULL)  		goto out; -	}  	dprintk("--> %s clp %p session %p sr_slot %td\n",  		__func__, session->clp, session, res->sr_slot ?  			res->sr_slot - session->fc_slot_table.slots : -1); -	ret = nfs41_setup_sequence(session, args, res, cache_reply, -				   task); +	ret = nfs41_setup_sequence(session, args, res, task);  out:  	dprintk("<-- %s status=%d\n", __func__, ret);  	return ret; @@ -629,7 +650,6 @@ struct nfs41_call_sync_data {  	const struct nfs_server *seq_server;  	struct nfs4_sequence_args *seq_args;  	struct nfs4_sequence_res *seq_res; -	int cache_reply;  };  static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) @@ -639,7 +659,7 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)  	dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);  	if (nfs4_setup_sequence(data->seq_server, data->seq_args, -				data->seq_res, data->cache_reply, task)) +				data->seq_res, task))  		return;  	rpc_call_start(task);  } @@ -657,12 +677,12 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)  	nfs41_sequence_done(task, data->seq_res);  } -struct rpc_call_ops nfs41_call_sync_ops = { +static const struct rpc_call_ops nfs41_call_sync_ops = {  	.rpc_call_prepare = nfs41_call_sync_prepare,  	.rpc_call_done = nfs41_call_sync_done,  }; -struct rpc_call_ops nfs41_call_priv_sync_ops = { +static const struct rpc_call_ops nfs41_call_priv_sync_ops = {  	.rpc_call_prepare = nfs41_call_priv_sync_prepare,  	.rpc_call_done = nfs41_call_sync_done,  }; @@ -672,7 +692,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,  				   struct rpc_message *msg,  				   struct nfs4_sequence_args *args,  				   struct nfs4_sequence_res *res, -				   int cache_reply,  				   int privileged)  {  	int ret; @@ -681,7 +700,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,  		.seq_server = server,  		.seq_args = args,  		.seq_res = res, -		.cache_reply = cache_reply,  	};  	struct rpc_task_setup task_setup = {  		.rpc_client = clnt, @@ -690,7 +708,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,  		.callback_data = &data  	}; -	res->sr_slot = NULL;  	if (privileged)  		task_setup.callback_ops = &nfs41_call_priv_sync_ops;  	task = rpc_run_task(&task_setup); @@ -710,10 +727,17 @@ int _nfs4_call_sync_session(struct rpc_clnt *clnt,  			    struct nfs4_sequence_res *res,  			    int cache_reply)  { -	return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0); +	nfs41_init_sequence(args, res, cache_reply); +	return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0);  }  #else +static inline +void nfs41_init_sequence(struct nfs4_sequence_args *args, +		struct nfs4_sequence_res *res, int cache_reply) +{ +} +  static int nfs4_sequence_done(struct rpc_task *task,  			       struct nfs4_sequence_res *res)  { @@ -728,7 +752,7 @@ int _nfs4_call_sync(struct rpc_clnt *clnt,  		    struct nfs4_sequence_res *res,  		    int cache_reply)  { -	args->sa_session = res->sr_session = NULL; +	nfs41_init_sequence(args, res, cache_reply);  	return rpc_call_sync(clnt, msg, 0);  } @@ -815,20 +839,22 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,  	p->o_arg.open_flags = flags;  	p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);  	p->o_arg.clientid = server->nfs_client->cl_clientid; -	p->o_arg.id = sp->so_owner_id.id; +	p->o_arg.id = sp->so_seqid.owner_id;  	p->o_arg.name = &dentry->d_name;  	p->o_arg.server = server;  	p->o_arg.bitmask = server->attr_bitmask;  	p->o_arg.dir_bitmask = server->cache_consistency_bitmask;  	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; -	if (flags & O_CREAT) { -		u32 *s; +	if (attrs != NULL && attrs->ia_valid != 0) { +		__be32 verf[2];  		p->o_arg.u.attrs = &p->attrs;  		memcpy(&p->attrs, attrs, sizeof(p->attrs)); -		s = (u32 *) p->o_arg.u.verifier.data; -		s[0] = jiffies; -		s[1] = current->pid; + +		verf[0] = jiffies; +		verf[1] = current->pid; +		memcpy(p->o_arg.u.verifier.data, verf, +				sizeof(p->o_arg.u.verifier.data));  	}  	p->c_arg.fh = &p->o_res.fh;  	p->c_arg.stateid = &p->o_res.stateid; @@ -878,7 +904,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode  {  	int ret = 0; -	if (open_mode & O_EXCL) +	if (open_mode & (O_EXCL|O_TRUNC))  		goto out;  	switch (mode & (FMODE_READ|FMODE_WRITE)) {  		case FMODE_READ: @@ -927,8 +953,8 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)  static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)  {  	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) -		memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); -	memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); +		nfs4_stateid_copy(&state->stateid, stateid); +	nfs4_stateid_copy(&state->open_stateid, stateid);  	switch (fmode) {  		case FMODE_READ:  			set_bit(NFS_O_RDONLY_STATE, &state->flags); @@ -956,7 +982,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s  	 */  	write_seqlock(&state->seqlock);  	if (deleg_stateid != NULL) { -		memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); +		nfs4_stateid_copy(&state->stateid, deleg_stateid);  		set_bit(NFS_DELEGATED_STATE, &state->flags);  	}  	if (open_stateid != NULL) @@ -987,7 +1013,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat  	if (delegation == NULL)  		delegation = &deleg_cur->stateid; -	else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0) +	else if (!nfs4_stateid_match(&deleg_cur->stateid, delegation))  		goto no_delegation_unlock;  	nfs_mark_delegation_referenced(deleg_cur); @@ -1026,7 +1052,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)  	struct nfs4_state *state = opendata->state;  	struct nfs_inode *nfsi = NFS_I(state->inode);  	struct nfs_delegation *delegation; -	int open_mode = opendata->o_arg.open_flags & O_EXCL; +	int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC);  	fmode_t fmode = opendata->o_arg.fmode;  	nfs4_stateid stateid;  	int ret = -EAGAIN; @@ -1048,7 +1074,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)  			break;  		}  		/* Save the delegation */ -		memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); +		nfs4_stateid_copy(&stateid, &delegation->stateid);  		rcu_read_unlock();  		ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);  		if (ret != 0) @@ -1090,6 +1116,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data  	if (state == NULL)  		goto err_put_inode;  	if (data->o_res.delegation_type != 0) { +		struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;  		int delegation_flags = 0;  		rcu_read_lock(); @@ -1101,7 +1128,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data  			pr_err_ratelimited("NFS: Broken NFSv4 server %s is "  					"returning a delegation for "  					"OPEN(CLAIM_DELEGATE_CUR)\n", -					NFS_CLIENT(inode)->cl_server); +					clp->cl_hostname);  		} else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)  			nfs_inode_set_delegation(state->inode,  					data->owner->so_cred, @@ -1210,10 +1237,10 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *  	 * Check if we need to update the current stateid.  	 */  	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && -	    memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { +	    !nfs4_stateid_match(&state->stateid, &state->open_stateid)) {  		write_seqlock(&state->seqlock);  		if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) -			memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); +			nfs4_stateid_copy(&state->stateid, &state->open_stateid);  		write_sequnlock(&state->seqlock);  	}  	return 0; @@ -1282,8 +1309,7 @@ static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs  	if (IS_ERR(opendata))  		return PTR_ERR(opendata);  	opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; -	memcpy(opendata->o_arg.u.delegation.data, stateid->data, -			sizeof(opendata->o_arg.u.delegation.data)); +	nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);  	ret = nfs4_open_recover(opendata, state);  	nfs4_opendata_put(opendata);  	return ret; @@ -1319,8 +1345,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state  				 * The show must go on: exit, but mark the  				 * stateid as needing recovery.  				 */ +			case -NFS4ERR_DELEG_REVOKED:  			case -NFS4ERR_ADMIN_REVOKED:  			case -NFS4ERR_BAD_STATEID: +				nfs_inode_find_state_and_recover(state->inode, +						stateid);  				nfs4_schedule_stateid_recovery(server, state);  			case -EKEYEXPIRED:  				/* @@ -1345,8 +1374,7 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)  	data->rpc_status = task->tk_status;  	if (data->rpc_status == 0) { -		memcpy(data->o_res.stateid.data, data->c_res.stateid.data, -				sizeof(data->o_res.stateid.data)); +		nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);  		nfs_confirm_seqid(&data->owner->so_seqid, 0);  		renew_lease(data->o_res.server, data->timestamp);  		data->rpc_done = 1; @@ -1440,7 +1468,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)  		rcu_read_unlock();  	}  	/* Update sequence id. */ -	data->o_arg.id = sp->so_owner_id.id; +	data->o_arg.id = sp->so_seqid.owner_id;  	data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;  	if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {  		task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; @@ -1449,7 +1477,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)  	data->timestamp = jiffies;  	if (nfs4_setup_sequence(data->o_arg.server,  				&data->o_arg.seq_args, -				&data->o_res.seq_res, 1, task)) +				&data->o_res.seq_res, task))  		return;  	rpc_call_start(task);  	return; @@ -1551,6 +1579,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)  	};  	int status; +	nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);  	kref_get(&data->kref);  	data->rpc_done = 0;  	data->rpc_status = 0; @@ -1712,15 +1741,32 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta  }  #if defined(CONFIG_NFS_V4_1) -static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) +static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags)  { -	int status; +	int status = NFS_OK;  	struct nfs_server *server = NFS_SERVER(state->inode); -	status = nfs41_test_stateid(server, state); -	if (status == NFS_OK) -		return 0; -	nfs41_free_stateid(server, state); +	if (state->flags & flags) { +		status = nfs41_test_stateid(server, stateid); +		if (status != NFS_OK) { +			nfs41_free_stateid(server, stateid); +			state->flags &= ~flags; +		} +	} +	return status; +} + +static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) +{ +	int deleg_status, open_status; +	int deleg_flags = 1 << NFS_DELEGATED_STATE; +	int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE); + +	deleg_status = nfs41_check_expired_stateid(state, &state->stateid, deleg_flags); +	open_status = nfs41_check_expired_stateid(state,  &state->open_stateid, open_flags); + +	if ((deleg_status == NFS_OK) && (open_status == NFS_OK)) +		return NFS_OK;  	return nfs4_open_expired(sp, state);  }  #endif @@ -1754,7 +1800,8 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode  	/* Protect against reboot recovery conflicts */  	status = -ENOMEM; -	if (!(sp = nfs4_get_state_owner(server, cred))) { +	sp = nfs4_get_state_owner(server, cred, GFP_KERNEL); +	if (sp == NULL) {  		dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");  		goto out_err;  	} @@ -1829,7 +1876,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry,  		 * the user though...  		 */  		if (status == -NFS4ERR_BAD_SEQID) { -			printk(KERN_WARNING "NFS: v4 server %s " +			pr_warn_ratelimited("NFS: v4 server %s "  					" returned a bad sequence-id error!\n",  					NFS_SERVER(dir)->nfs_client->cl_hostname);  			exception.retry = 1; @@ -1882,12 +1929,14 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,  	nfs_fattr_init(fattr); -	if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { +	if (state != NULL) { +		nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, +				current->files, current->tgid); +	} else if (nfs4_copy_delegation_stateid(&arg.stateid, inode, +				FMODE_WRITE)) {  		/* Use that stateid */ -	} else if (state != NULL) { -		nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid);  	} else -		memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); +		nfs4_stateid_copy(&arg.stateid, &zero_stateid);  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);  	if (status == 0 && state != NULL) @@ -1900,7 +1949,10 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,  			   struct nfs4_state *state)  {  	struct nfs_server *server = NFS_SERVER(inode); -	struct nfs4_exception exception = { }; +	struct nfs4_exception exception = { +		.state = state, +		.inode = inode, +	};  	int err;  	do {  		err = nfs4_handle_exception(server, @@ -1954,6 +2006,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)  	struct nfs4_state *state = calldata->state;  	struct nfs_server *server = NFS_SERVER(calldata->inode); +	dprintk("%s: begin!\n", __func__);  	if (!nfs4_sequence_done(task, &calldata->res.seq_res))  		return;          /* hmm. we are done with the inode, and in the process of freeing @@ -1981,6 +2034,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)  	}  	nfs_release_seqid(calldata->arg.seqid);  	nfs_refresh_inode(calldata->inode, calldata->res.fattr); +	dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);  }  static void nfs4_close_prepare(struct rpc_task *task, void *data) @@ -1989,6 +2043,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)  	struct nfs4_state *state = calldata->state;  	int call_close = 0; +	dprintk("%s: begin!\n", __func__);  	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)  		return; @@ -2013,7 +2068,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)  	if (!call_close) {  		/* Note: exit _without_ calling nfs4_close_done */  		task->tk_action = NULL; -		return; +		goto out;  	}  	if (calldata->arg.fmode == 0) { @@ -2022,17 +2077,20 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)  		    pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {  			rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,  				     task, NULL); -			return; +			goto out;  		}  	}  	nfs_fattr_init(calldata->res.fattr);  	calldata->timestamp = jiffies;  	if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), -				&calldata->arg.seq_args, &calldata->res.seq_res, -				1, task)) -		return; +				&calldata->arg.seq_args, +				&calldata->res.seq_res, +				task)) +		goto out;  	rpc_call_start(task); +out: +	dprintk("%s: done!\n", __func__);  }  static const struct rpc_call_ops nfs4_close_ops = { @@ -2074,6 +2132,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)  	calldata = kzalloc(sizeof(*calldata), gfp_mask);  	if (calldata == NULL)  		goto out; +	nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);  	calldata->inode = state->inode;  	calldata->state = state;  	calldata->arg.fh = NFS_FH(state->inode); @@ -2182,6 +2241,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f  		server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;  		server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;  		server->acl_bitmask = res.acl_bitmask; +		server->fh_expire_type = res.fh_expire_type;  	}  	return status; @@ -2303,7 +2363,6 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,  	return nfs4_map_errors(status);  } -static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);  /*   * Get locations and (maybe) other attributes of a referral.   * Note that we'll actually follow the referral later when @@ -2420,6 +2479,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,  		}  	} +	/* Deal with open(O_TRUNC) */ +	if (sattr->ia_valid & ATTR_OPEN) +		sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN); +  	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);  	if (status == 0)  		nfs_setattr_update_inode(inode, sattr); @@ -2494,7 +2557,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry  	struct nfs_server *server = NFS_SERVER(inode);  	struct nfs4_accessargs args = {  		.fh = NFS_FH(inode), -		.bitmask = server->attr_bitmask, +		.bitmask = server->cache_consistency_bitmask,  	};  	struct nfs4_accessres res = {  		.server = server, @@ -2712,8 +2775,18 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)  	args->bitmask = server->cache_consistency_bitmask;  	res->server = server; -	res->seq_res.sr_slot = NULL;  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; +	nfs41_init_sequence(&args->seq_args, &res->seq_res, 1); +} + +static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) +{ +	if (nfs4_setup_sequence(NFS_SERVER(data->dir), +				&data->args.seq_args, +				&data->res.seq_res, +				task)) +		return; +	rpc_call_start(task);  }  static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) @@ -2738,6 +2811,17 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];  	arg->bitmask = server->attr_bitmask;  	res->server = server; +	nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1); +} + +static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data) +{ +	if (nfs4_setup_sequence(NFS_SERVER(data->old_dir), +				&data->args.seq_args, +				&data->res.seq_res, +				task)) +		return; +	rpc_call_start(task);  }  static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, @@ -3232,6 +3316,17 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message  	data->timestamp   = jiffies;  	data->read_done_cb = nfs4_read_done_cb;  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; +	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); +} + +static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) +{ +	if (nfs4_setup_sequence(NFS_SERVER(data->inode), +				&data->args.seq_args, +				&data->res.seq_res, +				task)) +		return; +	rpc_call_start(task);  }  /* Reset the the nfs_read_data to send the read to the MDS. */ @@ -3305,6 +3400,17 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag  	data->timestamp   = jiffies;  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; +	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); +} + +static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) +{ +	if (nfs4_setup_sequence(NFS_SERVER(data->inode), +				&data->args.seq_args, +				&data->res.seq_res, +				task)) +		return; +	rpc_call_start(task);  }  static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data) @@ -3339,6 +3445,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa  		data->write_done_cb = nfs4_commit_done_cb;  	data->res.server = server;  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; +	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);  }  struct nfs4_renewdata { @@ -3575,8 +3682,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu  	}  	if (npages > 1) {  		/* for decoding across pages */ -		args.acl_scratch = alloc_page(GFP_KERNEL); -		if (!args.acl_scratch) +		res.acl_scratch = alloc_page(GFP_KERNEL); +		if (!res.acl_scratch)  			goto out_free;  	}  	args.acl_len = npages * PAGE_SIZE; @@ -3612,8 +3719,8 @@ out_free:  	for (i = 0; i < npages; i++)  		if (pages[i])  			__free_page(pages[i]); -	if (args.acl_scratch) -		__free_page(args.acl_scratch); +	if (res.acl_scratch) +		__free_page(res.acl_scratch);  	return ret;  } @@ -3714,8 +3821,11 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,  	if (task->tk_status >= 0)  		return 0;  	switch(task->tk_status) { +		case -NFS4ERR_DELEG_REVOKED:  		case -NFS4ERR_ADMIN_REVOKED:  		case -NFS4ERR_BAD_STATEID: +			if (state != NULL) +				nfs_remove_bad_delegation(state->inode);  		case -NFS4ERR_OPENMODE:  			if (state == NULL)  				break; @@ -3764,6 +3874,16 @@ wait_on_recovery:  	return -EAGAIN;  } +static void nfs4_construct_boot_verifier(struct nfs_client *clp, +					 nfs4_verifier *bootverf) +{ +	__be32 verf[2]; + +	verf[0] = htonl((u32)clp->cl_boot_time.tv_sec); +	verf[1] = htonl((u32)clp->cl_boot_time.tv_nsec); +	memcpy(bootverf->data, verf, sizeof(bootverf->data)); +} +  int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,  		unsigned short port, struct rpc_cred *cred,  		struct nfs4_setclientid_res *res) @@ -3780,15 +3900,13 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,  		.rpc_resp = res,  		.rpc_cred = cred,  	}; -	__be32 *p;  	int loop = 0;  	int status; -	p = (__be32*)sc_verifier.data; -	*p++ = htonl((u32)clp->cl_boot_time.tv_sec); -	*p = htonl((u32)clp->cl_boot_time.tv_nsec); +	nfs4_construct_boot_verifier(clp, &sc_verifier);  	for(;;) { +		rcu_read_lock();  		setclientid.sc_name_len = scnprintf(setclientid.sc_name,  				sizeof(setclientid.sc_name), "%s/%s %s %s %u",  				clp->cl_ipaddr, @@ -3805,6 +3923,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,  		setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,  				sizeof(setclientid.sc_uaddr), "%s.%u.%u",  				clp->cl_ipaddr, port >> 8, port & 255); +		rcu_read_unlock();  		status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);  		if (status != -NFS4ERR_CLID_INUSE) @@ -3891,7 +4010,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)  	if (nfs4_setup_sequence(d_data->res.server,  				&d_data->args.seq_args, -				&d_data->res.seq_res, 1, task)) +				&d_data->res.seq_res, task))  		return;  	rpc_call_start(task);  } @@ -3925,11 +4044,12 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co  	data = kzalloc(sizeof(*data), GFP_NOFS);  	if (data == NULL)  		return -ENOMEM; +	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);  	data->args.fhandle = &data->fh;  	data->args.stateid = &data->stateid;  	data->args.bitmask = server->attr_bitmask;  	nfs_copy_fh(&data->fh, NFS_FH(inode)); -	memcpy(&data->stateid, stateid, sizeof(data->stateid)); +	nfs4_stateid_copy(&data->stateid, stateid);  	data->res.fattr = &data->fattr;  	data->res.server = server;  	nfs_fattr_init(data->res.fattr); @@ -4016,7 +4136,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock  	if (status != 0)  		goto out;  	lsp = request->fl_u.nfs4_fl.owner; -	arg.lock_owner.id = lsp->ls_id.id; +	arg.lock_owner.id = lsp->ls_seqid.owner_id;  	arg.lock_owner.s_dev = server->s_dev;  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);  	switch (status) { @@ -4112,9 +4232,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)  		return;  	switch (task->tk_status) {  		case 0: -			memcpy(calldata->lsp->ls_stateid.data, -					calldata->res.stateid.data, -					sizeof(calldata->lsp->ls_stateid.data)); +			nfs4_stateid_copy(&calldata->lsp->ls_stateid, +					&calldata->res.stateid);  			renew_lease(calldata->server, calldata->timestamp);  			break;  		case -NFS4ERR_BAD_STATEID: @@ -4142,7 +4261,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)  	calldata->timestamp = jiffies;  	if (nfs4_setup_sequence(calldata->server,  				&calldata->arg.seq_args, -				&calldata->res.seq_res, 1, task)) +				&calldata->res.seq_res, task))  		return;  	rpc_call_start(task);  } @@ -4182,6 +4301,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,  		return ERR_PTR(-ENOMEM);  	} +	nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);  	msg.rpc_argp = &data->arg;  	msg.rpc_resp = &data->res;  	task_setup_data.callback_data = data; @@ -4261,7 +4381,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,  		goto out_free_seqid;  	p->arg.lock_stateid = &lsp->ls_stateid;  	p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; -	p->arg.lock_owner.id = lsp->ls_id.id; +	p->arg.lock_owner.id = lsp->ls_seqid.owner_id;  	p->arg.lock_owner.s_dev = server->s_dev;  	p->res.lock_seqid = p->arg.lock_seqid;  	p->lsp = lsp; @@ -4297,7 +4417,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)  	data->timestamp = jiffies;  	if (nfs4_setup_sequence(data->server,  				&data->arg.seq_args, -				&data->res.seq_res, 1, task)) +				&data->res.seq_res, task))  		return;  	rpc_call_start(task);  	dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); @@ -4326,8 +4446,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)  			goto out;  	}  	if (data->rpc_status == 0) { -		memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, -					sizeof(data->lsp->ls_stateid.data)); +		nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);  		data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;  		renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);  	} @@ -4415,6 +4534,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f  			data->arg.reclaim = NFS_LOCK_RECLAIM;  		task_setup_data.callback_ops = &nfs4_recover_lock_ops;  	} +	nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);  	msg.rpc_argp = &data->arg;  	msg.rpc_resp = &data->res;  	task_setup_data.callback_data = data; @@ -4479,15 +4599,34 @@ out:  }  #if defined(CONFIG_NFS_V4_1) -static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request) +static int nfs41_check_expired_locks(struct nfs4_state *state)  { -	int status; +	int status, ret = NFS_OK; +	struct nfs4_lock_state *lsp;  	struct nfs_server *server = NFS_SERVER(state->inode); -	status = nfs41_test_stateid(server, state); +	list_for_each_entry(lsp, &state->lock_states, ls_locks) { +		if (lsp->ls_flags & NFS_LOCK_INITIALIZED) { +			status = nfs41_test_stateid(server, &lsp->ls_stateid); +			if (status != NFS_OK) { +				nfs41_free_stateid(server, &lsp->ls_stateid); +				lsp->ls_flags &= ~NFS_LOCK_INITIALIZED; +				ret = status; +			} +		} +	}; + +	return ret; +} + +static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request) +{ +	int status = NFS_OK; + +	if (test_bit(LK_STATE_IN_USE, &state->flags)) +		status = nfs41_check_expired_locks(state);  	if (status == NFS_OK) -		return 0; -	nfs41_free_stateid(server, state); +		return status;  	return nfs4_lock_expired(state, request);  }  #endif @@ -4523,7 +4662,8 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock  	/* Note: we always want to sleep here! */  	request->fl_flags = fl_flags | FL_SLEEP;  	if (do_vfs_lock(request->fl_file, request) < 0) -		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); +		printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock " +			"manager!\n", __func__);  out_unlock:  	up_read(&nfsi->rwsem);  out: @@ -4533,7 +4673,9 @@ out:  static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)  { -	struct nfs4_exception exception = { }; +	struct nfs4_exception exception = { +		.state = state, +	};  	int err;  	do { @@ -4603,8 +4745,8 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)  		err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);  		switch (err) {  			default: -				printk(KERN_ERR "%s: unhandled error %d.\n", -						__func__, err); +				printk(KERN_ERR "NFS: %s: unhandled error " +					"%d.\n", __func__, err);  			case 0:  			case -ESTALE:  				goto out; @@ -4626,6 +4768,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)  				 * The show must go on: exit, but mark the  				 * stateid as needing recovery.  				 */ +			case -NFS4ERR_DELEG_REVOKED:  			case -NFS4ERR_ADMIN_REVOKED:  			case -NFS4ERR_BAD_STATEID:  			case -NFS4ERR_OPENMODE: @@ -4655,33 +4798,44 @@ out:  	return err;  } +struct nfs_release_lockowner_data { +	struct nfs4_lock_state *lsp; +	struct nfs_server *server; +	struct nfs_release_lockowner_args args; +}; +  static void nfs4_release_lockowner_release(void *calldata)  { +	struct nfs_release_lockowner_data *data = calldata; +	nfs4_free_lock_state(data->server, data->lsp);  	kfree(calldata);  } -const struct rpc_call_ops nfs4_release_lockowner_ops = { +static const struct rpc_call_ops nfs4_release_lockowner_ops = {  	.rpc_release = nfs4_release_lockowner_release,  }; -void nfs4_release_lockowner(const struct nfs4_lock_state *lsp) +int nfs4_release_lockowner(struct nfs4_lock_state *lsp)  {  	struct nfs_server *server = lsp->ls_state->owner->so_server; -	struct nfs_release_lockowner_args *args; +	struct nfs_release_lockowner_data *data;  	struct rpc_message msg = {  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],  	};  	if (server->nfs_client->cl_mvops->minor_version != 0) -		return; -	args = kmalloc(sizeof(*args), GFP_NOFS); -	if (!args) -		return; -	args->lock_owner.clientid = server->nfs_client->cl_clientid; -	args->lock_owner.id = lsp->ls_id.id; -	args->lock_owner.s_dev = server->s_dev; -	msg.rpc_argp = args; -	rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); +		return -EINVAL; +	data = kmalloc(sizeof(*data), GFP_NOFS); +	if (!data) +		return -ENOMEM; +	data->lsp = lsp; +	data->server = server; +	data->args.lock_owner.clientid = server->nfs_client->cl_clientid; +	data->args.lock_owner.id = lsp->ls_seqid.owner_id; +	data->args.lock_owner.s_dev = server->s_dev; +	msg.rpc_argp = &data->args; +	rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data); +	return 0;  }  #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" @@ -4727,11 +4881,11 @@ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)  	if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||  	       (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&  	      (fattr->valid & NFS_ATTR_FATTR_FSID) && -	      (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL))) +	      (fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)))  		return;  	fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | -		NFS_ATTR_FATTR_NLINK; +		NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_V4_REFERRAL;  	fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;  	fattr->nlink = 2;  } @@ -4798,7 +4952,8 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct  	return status;  } -int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) +static int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, +		struct nfs4_secinfo_flavors *flavors)  {  	struct nfs4_exception exception = { };  	int err; @@ -4852,6 +5007,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)  {  	nfs4_verifier verifier;  	struct nfs41_exchange_id_args args = { +		.verifier = &verifier,  		.client = clp,  		.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,  	}; @@ -4865,15 +5021,11 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)  		.rpc_resp = &res,  		.rpc_cred = cred,  	}; -	__be32 *p;  	dprintk("--> %s\n", __func__);  	BUG_ON(clp == NULL); -	p = (u32 *)verifier.data; -	*p++ = htonl((u32)clp->cl_boot_time.tv_sec); -	*p = htonl((u32)clp->cl_boot_time.tv_nsec); -	args.verifier = &verifier; +	nfs4_construct_boot_verifier(clp, &verifier);  	args.id_len = scnprintf(args.id, sizeof(args.id),  				"%s/%s.%s/%u", @@ -4883,14 +5035,29 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)  				clp->cl_rpcclient->cl_auth->au_flavor);  	res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL); -	if (unlikely(!res.server_scope)) -		return -ENOMEM; +	if (unlikely(!res.server_scope)) { +		status = -ENOMEM; +		goto out; +	} + +	res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_KERNEL); +	if (unlikely(!res.impl_id)) { +		status = -ENOMEM; +		goto out_server_scope; +	}  	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);  	if (!status)  		status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);  	if (!status) { +		/* use the most recent implementation id */ +		kfree(clp->impl_id); +		clp->impl_id = res.impl_id; +	} else +		kfree(res.impl_id); + +	if (!status) {  		if (clp->server_scope &&  		    !nfs41_same_server_scope(clp->server_scope,  					     res.server_scope)) { @@ -4901,12 +5068,21 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)  			clp->server_scope = NULL;  		} -		if (!clp->server_scope) +		if (!clp->server_scope) {  			clp->server_scope = res.server_scope; -		else -			kfree(res.server_scope); +			goto out; +		}  	} +out_server_scope: +	kfree(res.server_scope); +out: +	if (clp->impl_id) +		dprintk("%s: Server Implementation ID: " +			"domain: %s, name: %s, date: %llu,%u\n", +			__func__, clp->impl_id->domain, clp->impl_id->name, +			clp->impl_id->date.seconds, +			clp->impl_id->date.nseconds);  	dprintk("<-- %s status= %d\n", __func__, status);  	return status;  } @@ -4930,7 +5106,7 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task,  	   since we're invoked within one */  	ret = nfs41_setup_sequence(data->clp->cl_session,  				   &data->args->la_seq_args, -				   &data->res->lr_seq_res, 0, task); +				   &data->res->lr_seq_res, task);  	BUG_ON(ret == -EAGAIN);  	rpc_call_start(task); @@ -4963,7 +5139,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)  	dprintk("<-- %s\n", __func__);  } -struct rpc_call_ops nfs4_get_lease_time_ops = { +static const struct rpc_call_ops nfs4_get_lease_time_ops = {  	.rpc_call_prepare = nfs4_get_lease_time_prepare,  	.rpc_call_done = nfs4_get_lease_time_done,  }; @@ -4994,6 +5170,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)  	};  	int status; +	nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);  	dprintk("--> %s\n", __func__);  	task = rpc_run_task(&task_setup); @@ -5008,37 +5185,53 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)  	return status;  } +static struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags) +{ +	return kcalloc(max_slots, sizeof(struct nfs4_slot), gfp_flags); +} + +static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, +		struct nfs4_slot *new, +		u32 max_slots, +		u32 ivalue) +{ +	struct nfs4_slot *old = NULL; +	u32 i; + +	spin_lock(&tbl->slot_tbl_lock); +	if (new) { +		old = tbl->slots; +		tbl->slots = new; +		tbl->max_slots = max_slots; +	} +	tbl->highest_used_slotid = -1;	/* no slot is currently used */ +	for (i = 0; i < tbl->max_slots; i++) +		tbl->slots[i].seq_nr = ivalue; +	spin_unlock(&tbl->slot_tbl_lock); +	kfree(old); +} +  /* - * Reset a slot table + * (re)Initialise a slot table   */ -static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, -				 int ivalue) +static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, +				 u32 ivalue)  {  	struct nfs4_slot *new = NULL; -	int i; -	int ret = 0; +	int ret = -ENOMEM;  	dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__,  		max_reqs, tbl->max_slots);  	/* Does the newly negotiated max_reqs match the existing slot table? */  	if (max_reqs != tbl->max_slots) { -		ret = -ENOMEM; -		new = kmalloc(max_reqs * sizeof(struct nfs4_slot), -			      GFP_NOFS); +		new = nfs4_alloc_slots(max_reqs, GFP_NOFS);  		if (!new)  			goto out; -		ret = 0; -		kfree(tbl->slots); -	} -	spin_lock(&tbl->slot_tbl_lock); -	if (new) { -		tbl->slots = new; -		tbl->max_slots = max_reqs;  	} -	for (i = 0; i < tbl->max_slots; ++i) -		tbl->slots[i].seq_nr = ivalue; -	spin_unlock(&tbl->slot_tbl_lock); +	ret = 0; + +	nfs4_add_and_init_slots(tbl, new, max_reqs, ivalue);  	dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,  		tbl, tbl->slots, tbl->max_slots);  out: @@ -5061,36 +5254,6 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session)  }  /* - * Initialize slot table - */ -static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, -		int max_slots, int ivalue) -{ -	struct nfs4_slot *slot; -	int ret = -ENOMEM; - -	BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); - -	dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); - -	slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS); -	if (!slot) -		goto out; -	ret = 0; - -	spin_lock(&tbl->slot_tbl_lock); -	tbl->max_slots = max_slots; -	tbl->slots = slot; -	tbl->highest_used_slotid = -1;  /* no slot is currently used */ -	spin_unlock(&tbl->slot_tbl_lock); -	dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, -		tbl, tbl->slots, tbl->max_slots); -out: -	dprintk("<-- %s: return %d\n", __func__, ret); -	return ret; -} - -/*   * Initialize or reset the forechannel and backchannel tables   */  static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) @@ -5101,25 +5264,16 @@ static int nfs4_setup_session_slot_tables(struct nfs4_session *ses)  	dprintk("--> %s\n", __func__);  	/* Fore channel */  	tbl = &ses->fc_slot_table; -	if (tbl->slots == NULL) { -		status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1); -		if (status) /* -ENOMEM */ -			return status; -	} else { -		status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1); -		if (status) -			return status; -	} +	status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); +	if (status) /* -ENOMEM */ +		return status;  	/* Back channel */  	tbl = &ses->bc_slot_table; -	if (tbl->slots == NULL) { -		status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0); -		if (status) -			/* Fore and back channel share a connection so get -			 * both slot tables or neither */ -			nfs4_destroy_slot_tables(ses); -	} else -		status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0); +	status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); +	if (status && tbl->slots == NULL) +		/* Fore and back channel share a connection so get +		 * both slot tables or neither */ +		nfs4_destroy_slot_tables(ses);  	return status;  } @@ -5133,13 +5287,13 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)  		return NULL;  	tbl = &session->fc_slot_table; -	tbl->highest_used_slotid = -1; +	tbl->highest_used_slotid = NFS4_NO_SLOT;  	spin_lock_init(&tbl->slot_tbl_lock);  	rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");  	init_completion(&tbl->complete);  	tbl = &session->bc_slot_table; -	tbl->highest_used_slotid = -1; +	tbl->highest_used_slotid = NFS4_NO_SLOT;  	spin_lock_init(&tbl->slot_tbl_lock);  	rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");  	init_completion(&tbl->complete); @@ -5152,11 +5306,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)  void nfs4_destroy_session(struct nfs4_session *session)  { +	struct rpc_xprt *xprt; +  	nfs4_proc_destroy_session(session); + +	rcu_read_lock(); +	xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); +	rcu_read_unlock();  	dprintk("%s Destroy backchannel for xprt %p\n", -		__func__, session->clp->cl_rpcclient->cl_xprt); -	xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, -				NFS41_BC_MIN_CALLBACKS); +		__func__, xprt); +	xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);  	nfs4_destroy_slot_tables(session);  	kfree(session);  } @@ -5184,7 +5343,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)  	args->fc_attrs.max_rqst_sz = mxrqst_sz;  	args->fc_attrs.max_resp_sz = mxresp_sz;  	args->fc_attrs.max_ops = NFS4_MAX_OPS; -	args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; +	args->fc_attrs.max_reqs = max_session_slots;  	dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "  		"max_ops=%u max_reqs=%u\n", @@ -5224,6 +5383,8 @@ static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args  		return -EINVAL;  	if (rcvd->max_reqs == 0)  		return -EINVAL; +	if (rcvd->max_reqs > NFS4_MAX_SLOT_TABLE) +		rcvd->max_reqs = NFS4_MAX_SLOT_TABLE;  	return 0;  } @@ -5239,9 +5400,9 @@ static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args  	if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)  		return -EINVAL;  	/* These would render the backchannel useless: */ -	if (rcvd->max_ops  == 0) +	if (rcvd->max_ops != sent->max_ops)  		return -EINVAL; -	if (rcvd->max_reqs == 0) +	if (rcvd->max_reqs != sent->max_reqs)  		return -EINVAL;  	return 0;  } @@ -5344,7 +5505,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)  	if (status)  		printk(KERN_WARNING -			"Got error %d from the server on DESTROY_SESSION. " +			"NFS: Got error %d from the server on DESTROY_SESSION. "  			"Session has been destroyed regardless...\n", status);  	dprintk("<-- nfs4_proc_destroy_session\n"); @@ -5467,7 +5628,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)  	args = task->tk_msg.rpc_argp;  	res = task->tk_msg.rpc_resp; -	if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task)) +	if (nfs41_setup_sequence(clp->cl_session, args, res, task))  		return;  	rpc_call_start(task);  } @@ -5499,6 +5660,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_  		nfs_put_client(clp);  		return ERR_PTR(-ENOMEM);  	} +	nfs41_init_sequence(&calldata->args, &calldata->res, 0);  	msg.rpc_argp = &calldata->args;  	msg.rpc_resp = &calldata->res;  	calldata->clp = clp; @@ -5560,7 +5722,7 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)  	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);  	if (nfs41_setup_sequence(calldata->clp->cl_session,  				&calldata->arg.seq_args, -				&calldata->res.seq_res, 0, task)) +				&calldata->res.seq_res, task))  		return;  	rpc_call_start(task); @@ -5639,6 +5801,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)  	calldata->clp = clp;  	calldata->arg.one_fs = 0; +	nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);  	msg.rpc_argp = &calldata->arg;  	msg.rpc_resp = &calldata->res;  	task_setup_data.callback_data = calldata; @@ -5670,7 +5833,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)  	 * to be no way to prevent it completely.  	 */  	if (nfs4_setup_sequence(server, &lgp->args.seq_args, -				&lgp->res.seq_res, 0, task)) +				&lgp->res.seq_res, task))  		return;  	if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,  					  NFS_I(lgp->args.inode)->layout, @@ -5745,6 +5908,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)  	lgp->res.layoutp = &lgp->args.layout;  	lgp->res.seq_res.sr_slot = NULL; +	nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);  	task = rpc_run_task(&task_setup_data);  	if (IS_ERR(task))  		return PTR_ERR(task); @@ -5765,7 +5929,7 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)  	dprintk("--> %s\n", __func__);  	if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args, -				&lrp->res.seq_res, 0, task)) +				&lrp->res.seq_res, task))  		return;  	rpc_call_start(task);  } @@ -5831,6 +5995,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)  	int status;  	dprintk("--> %s\n", __func__); +	nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);  	task = rpc_run_task(&task_setup_data);  	if (IS_ERR(task))  		return PTR_ERR(task); @@ -5931,7 +6096,7 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)  	struct nfs_server *server = NFS_SERVER(data->args.inode);  	if (nfs4_setup_sequence(server, &data->args.seq_args, -				&data->res.seq_res, 1, task)) +				&data->res.seq_res, task))  		return;  	rpc_call_start(task);  } @@ -6018,6 +6183,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)  		data->args.lastbytewritten,  		data->args.inode->i_ino); +	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);  	task = rpc_run_task(&task_setup_data);  	if (IS_ERR(task))  		return PTR_ERR(task); @@ -6111,11 +6277,12 @@ out_freepage:  out:  	return err;  } -static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) + +static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)  {  	int status;  	struct nfs41_test_stateid_args args = { -		.stateid = &state->stateid, +		.stateid = stateid,  	};  	struct nfs41_test_stateid_res res;  	struct rpc_message msg = { @@ -6123,28 +6290,31 @@ static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *sta  		.rpc_argp = &args,  		.rpc_resp = &res,  	}; -	args.seq_args.sa_session = res.seq_res.sr_session = NULL; -	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); + +	nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); +	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); + +	if (status == NFS_OK) +		return res.status;  	return status;  } -static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) +static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)  {  	struct nfs4_exception exception = { };  	int err;  	do {  		err = nfs4_handle_exception(server, -				_nfs41_test_stateid(server, state), +				_nfs41_test_stateid(server, stateid),  				&exception);  	} while (exception.retry);  	return err;  } -static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state) +static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)  { -	int status;  	struct nfs41_free_stateid_args args = { -		.stateid = &state->stateid, +		.stateid = stateid,  	};  	struct nfs41_free_stateid_res res;  	struct rpc_message msg = { @@ -6153,25 +6323,46 @@ static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *stat  		.rpc_resp = &res,  	}; -	args.seq_args.sa_session = res.seq_res.sr_session = NULL; -	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); -	return status; +	nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); +	return nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);  } -static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state) +static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)  {  	struct nfs4_exception exception = { };  	int err;  	do {  		err = nfs4_handle_exception(server, -				_nfs4_free_stateid(server, state), +				_nfs4_free_stateid(server, stateid),  				&exception);  	} while (exception.retry);  	return err;  } + +static bool nfs41_match_stateid(const nfs4_stateid *s1, +		const nfs4_stateid *s2) +{ +	if (memcmp(s1->other, s2->other, sizeof(s1->other)) != 0) +		return false; + +	if (s1->seqid == s2->seqid) +		return true; +	if (s1->seqid == 0 || s2->seqid == 0) +		return true; + +	return false; +} +  #endif /* CONFIG_NFS_V4_1 */ -struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { +static bool nfs4_match_stateid(const nfs4_stateid *s1, +		const nfs4_stateid *s2) +{ +	return nfs4_stateid_match(s1, s2); +} + + +static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {  	.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,  	.state_flag_bit	= NFS_STATE_RECLAIM_REBOOT,  	.recover_open	= nfs4_open_reclaim, @@ -6181,7 +6372,7 @@ struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {  };  #if defined(CONFIG_NFS_V4_1) -struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { +static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {  	.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,  	.state_flag_bit	= NFS_STATE_RECLAIM_REBOOT,  	.recover_open	= nfs4_open_reclaim, @@ -6192,7 +6383,7 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {  };  #endif /* CONFIG_NFS_V4_1 */ -struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { +static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {  	.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,  	.state_flag_bit	= NFS_STATE_RECLAIM_NOGRACE,  	.recover_open	= nfs4_open_expired, @@ -6202,7 +6393,7 @@ struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {  };  #if defined(CONFIG_NFS_V4_1) -struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { +static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {  	.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,  	.state_flag_bit	= NFS_STATE_RECLAIM_NOGRACE,  	.recover_open	= nfs41_open_expired, @@ -6212,14 +6403,14 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {  };  #endif /* CONFIG_NFS_V4_1 */ -struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { +static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {  	.sched_state_renewal = nfs4_proc_async_renew,  	.get_state_renewal_cred_locked = nfs4_get_renew_cred_locked,  	.renew_lease = nfs4_proc_renew,  };  #if defined(CONFIG_NFS_V4_1) -struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { +static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {  	.sched_state_renewal = nfs41_proc_async_sequence,  	.get_state_renewal_cred_locked = nfs4_get_machine_cred_locked,  	.renew_lease = nfs4_proc_sequence, @@ -6229,7 +6420,7 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {  static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {  	.minor_version = 0,  	.call_sync = _nfs4_call_sync, -	.validate_stateid = nfs4_validate_delegation_stateid, +	.match_stateid = nfs4_match_stateid,  	.find_root_sec = nfs4_find_root_sec,  	.reboot_recovery_ops = &nfs40_reboot_recovery_ops,  	.nograce_recovery_ops = &nfs40_nograce_recovery_ops, @@ -6240,7 +6431,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {  static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {  	.minor_version = 1,  	.call_sync = _nfs4_call_sync_session, -	.validate_stateid = nfs41_validate_delegation_stateid, +	.match_stateid = nfs41_match_stateid,  	.find_root_sec = nfs41_find_root_sec,  	.reboot_recovery_ops = &nfs41_reboot_recovery_ops,  	.nograce_recovery_ops = &nfs41_nograce_recovery_ops, @@ -6280,9 +6471,11 @@ const struct nfs_rpc_ops nfs_v4_clientops = {  	.create		= nfs4_proc_create,  	.remove		= nfs4_proc_remove,  	.unlink_setup	= nfs4_proc_unlink_setup, +	.unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,  	.unlink_done	= nfs4_proc_unlink_done,  	.rename		= nfs4_proc_rename,  	.rename_setup	= nfs4_proc_rename_setup, +	.rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,  	.rename_done	= nfs4_proc_rename_done,  	.link		= nfs4_proc_link,  	.symlink	= nfs4_proc_symlink, @@ -6296,8 +6489,10 @@ const struct nfs_rpc_ops nfs_v4_clientops = {  	.set_capabilities = nfs4_server_capabilities,  	.decode_dirent	= nfs4_decode_dirent,  	.read_setup	= nfs4_proc_read_setup, +	.read_rpc_prepare = nfs4_proc_read_rpc_prepare,  	.read_done	= nfs4_read_done,  	.write_setup	= nfs4_proc_write_setup, +	.write_rpc_prepare = nfs4_proc_write_rpc_prepare,  	.write_done	= nfs4_write_done,  	.commit_setup	= nfs4_proc_commit_setup,  	.commit_done	= nfs4_commit_done, @@ -6321,6 +6516,10 @@ const struct xattr_handler *nfs4_xattr_handlers[] = {  	NULL  }; +module_param(max_session_slots, ushort, 0644); +MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 " +		"requests the client will negotiate"); +  /*   * Local variables:   *  c-basic-offset: 8 | 
