diff options
| -rw-r--r-- | fs/nfs/inode.c | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs4filelayout.c | 6 | ||||
| -rw-r--r-- | fs/nfs/nfs4filelayout.h | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 21 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 21 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 6 | ||||
| -rw-r--r-- | fs/nfs/unlink.c | 20 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 1 | ||||
| -rw-r--r-- | include/linux/sunrpc/clnt.h | 1 | ||||
| -rw-r--r-- | net/sunrpc/clnt.c | 15 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 6 | 
11 files changed, 77 insertions, 24 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b586fe9af47..1f941674b08 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -237,6 +237,8 @@ nfs_find_actor(struct inode *inode, void *opaque)  	if (NFS_FILEID(inode) != fattr->fileid)  		return 0; +	if ((S_IFMT & inode->i_mode) != (S_IFMT & fattr->mode)) +		return 0;  	if (nfs_compare_fh(NFS_FH(inode), fh))  		return 0;  	if (is_bad_inode(inode) || NFS_STALE(inode)) diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 194c4841033..49eeb044c10 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -99,7 +99,8 @@ static void filelayout_reset_write(struct nfs_write_data *data)  		task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode,  							&hdr->pages, -							hdr->completion_ops); +							hdr->completion_ops, +							hdr->dreq);  	}  } @@ -119,7 +120,8 @@ static void filelayout_reset_read(struct nfs_read_data *data)  		task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode,  							&hdr->pages, -							hdr->completion_ops); +							hdr->completion_ops, +							hdr->dreq);  	}  } diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 8c07241fe52..b8da95548d3 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h @@ -36,7 +36,7 @@   * Default data server connection timeout and retrans vaules.   * Set by module paramters dataserver_timeo and dataserver_retrans.   */ -#define NFS4_DEF_DS_TIMEO   60 +#define NFS4_DEF_DS_TIMEO   600 /* in tenths of a second */  #define NFS4_DEF_DS_RETRANS 5  /* diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index eae83bf96c6..b2671cb0f90 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -93,6 +93,8 @@ static int nfs4_map_errors(int err)  		return err;  	switch (err) {  	case -NFS4ERR_RESOURCE: +	case -NFS4ERR_LAYOUTTRYLATER: +	case -NFS4ERR_RECALLCONFLICT:  		return -EREMOTEIO;  	case -NFS4ERR_WRONGSEC:  		return -EPERM; @@ -1158,6 +1160,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)  			data->o_arg.fmode);  	iput(inode);  out: +	nfs_release_seqid(data->o_arg.seqid);  	return state;  err_put_inode:  	iput(inode); @@ -6045,6 +6048,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)  	struct nfs_server *server = NFS_SERVER(inode);  	struct pnfs_layout_hdr *lo;  	struct nfs4_state *state = NULL; +	unsigned long timeo, giveup;  	dprintk("--> %s\n", __func__); @@ -6056,7 +6060,10 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)  		goto out;  	case -NFS4ERR_LAYOUTTRYLATER:  	case -NFS4ERR_RECALLCONFLICT: -		task->tk_status = -NFS4ERR_DELAY; +		timeo = rpc_get_timeout(task->tk_client); +		giveup = lgp->args.timestamp + timeo; +		if (time_after(giveup, jiffies)) +			task->tk_status = -NFS4ERR_DELAY;  		break;  	case -NFS4ERR_EXPIRED:  	case -NFS4ERR_BAD_STATEID: @@ -6129,11 +6136,13 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)  static void nfs4_layoutget_release(void *calldata)  {  	struct nfs4_layoutget *lgp = calldata; -	struct nfs_server *server = NFS_SERVER(lgp->args.inode); +	struct inode *inode = lgp->args.inode; +	struct nfs_server *server = NFS_SERVER(inode);  	size_t max_pages = max_response_pages(server);  	dprintk("--> %s\n", __func__);  	nfs4_free_pages(lgp->args.layout.pages, max_pages); +	pnfs_put_layout_hdr(NFS_I(inode)->layout);  	put_nfs_open_context(lgp->args.ctx);  	kfree(calldata);  	dprintk("<-- %s\n", __func__); @@ -6148,7 +6157,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {  struct pnfs_layout_segment *  nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)  { -	struct nfs_server *server = NFS_SERVER(lgp->args.inode); +	struct inode *inode = lgp->args.inode; +	struct nfs_server *server = NFS_SERVER(inode);  	size_t max_pages = max_response_pages(server);  	struct rpc_task *task;  	struct rpc_message msg = { @@ -6174,10 +6184,15 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)  		return ERR_PTR(-ENOMEM);  	}  	lgp->args.layout.pglen = max_pages * PAGE_SIZE; +	lgp->args.timestamp = jiffies;  	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); + +	/* nfs4_layoutget_release calls pnfs_put_layout_hdr */ +	pnfs_get_layout_hdr(NFS_I(inode)->layout); +  	task = rpc_run_task(&task_setup_data);  	if (IS_ERR(task))  		return ERR_CAST(task); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 6be70f622b6..48ac5aad625 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1181,7 +1181,7 @@ pnfs_update_layout(struct inode *ino,  	struct nfs_client *clp = server->nfs_client;  	struct pnfs_layout_hdr *lo;  	struct pnfs_layout_segment *lseg = NULL; -	bool first = false; +	bool first;  	if (!pnfs_enabled_sb(NFS_SERVER(ino)))  		goto out; @@ -1215,10 +1215,9 @@ pnfs_update_layout(struct inode *ino,  		goto out_unlock;  	atomic_inc(&lo->plh_outstanding); -	if (list_empty(&lo->plh_segs)) -		first = true; - +	first = list_empty(&lo->plh_layouts) ? true : false;  	spin_unlock(&ino->i_lock); +  	if (first) {  		/* The lo must be on the clp list if there is any  		 * chance of a CB_LAYOUTRECALL(FILE) coming in. @@ -1422,13 +1421,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);  int pnfs_write_done_resend_to_mds(struct inode *inode,  				struct list_head *head, -				const struct nfs_pgio_completion_ops *compl_ops) +				const struct nfs_pgio_completion_ops *compl_ops, +				struct nfs_direct_req *dreq)  {  	struct nfs_pageio_descriptor pgio;  	LIST_HEAD(failed);  	/* Resend all requests through the MDS */  	nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); +	pgio.pg_dreq = dreq;  	while (!list_empty(head)) {  		struct nfs_page *req = nfs_list_entry(head->next); @@ -1463,7 +1464,8 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)  	if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))  		data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode,  							&hdr->pages, -							hdr->completion_ops); +							hdr->completion_ops, +							hdr->dreq);  }  /* @@ -1578,13 +1580,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);  int pnfs_read_done_resend_to_mds(struct inode *inode,  				struct list_head *head, -				const struct nfs_pgio_completion_ops *compl_ops) +				const struct nfs_pgio_completion_ops *compl_ops, +				struct nfs_direct_req *dreq)  {  	struct nfs_pageio_descriptor pgio;  	LIST_HEAD(failed);  	/* Resend all requests through the MDS */  	nfs_pageio_init_read(&pgio, inode, compl_ops); +	pgio.pg_dreq = dreq;  	while (!list_empty(head)) {  		struct nfs_page *req = nfs_list_entry(head->next); @@ -1615,7 +1619,8 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)  	if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))  		data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode,  							&hdr->pages, -							hdr->completion_ops); +							hdr->completion_ops, +							hdr->dreq);  }  /* diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 97cb358bb88..94ba8041774 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -230,9 +230,11 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,  void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp);  int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, -			const struct nfs_pgio_completion_ops *compl_ops); +			const struct nfs_pgio_completion_ops *compl_ops, +			struct nfs_direct_req *dreq);  int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, -			const struct nfs_pgio_completion_ops *compl_ops); +			const struct nfs_pgio_completion_ops *compl_ops, +			struct nfs_direct_req *dreq);  struct nfs4_threshold *pnfs_mdsthreshold_alloc(void);  /* nfs4_deviceid_flags */ diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index d26a32f5b53..1f1f38f0c5d 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -335,20 +335,14 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)  	struct inode *old_dir = data->old_dir;  	struct inode *new_dir = data->new_dir;  	struct dentry *old_dentry = data->old_dentry; -	struct dentry *new_dentry = data->new_dentry;  	if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {  		rpc_restart_call_prepare(task);  		return;  	} -	if (task->tk_status != 0) { +	if (task->tk_status != 0)  		nfs_cancel_async_unlink(old_dentry); -		return; -	} - -	d_drop(old_dentry); -	d_drop(new_dentry);  }  /** @@ -549,6 +543,18 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)  	error = rpc_wait_for_completion_task(task);  	if (error == 0)  		error = task->tk_status; +	switch (error) { +	case 0: +		/* The rename succeeded */ +		nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); +		d_move(dentry, sdentry); +		break; +	case -ERESTARTSYS: +		/* The result of the rename is unknown. Play it safe by +		 * forcing a new lookup */ +		d_drop(dentry); +		d_drop(sdentry); +	}  	rpc_put_task(task);  out_dput:  	dput(sdentry); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 13441ddac33..4b993d358da 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -233,6 +233,7 @@ struct nfs4_layoutget_args {  	struct inode *inode;  	struct nfs_open_context *ctx;  	nfs4_stateid stateid; +	unsigned long timestamp;  	struct nfs4_layoutdriver_data layout;  }; diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 4a4abde000c..2cf4ffaa3cd 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -160,6 +160,7 @@ void		rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);  int		rpc_protocol(struct rpc_clnt *);  struct net *	rpc_net_ns(struct rpc_clnt *);  size_t		rpc_max_payload(struct rpc_clnt *); +unsigned long	rpc_get_timeout(struct rpc_clnt *clnt);  void		rpc_force_rebind(struct rpc_clnt *);  size_t		rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);  const char	*rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d7a369e6108..dcc446e7fbf 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1197,6 +1197,21 @@ size_t rpc_max_payload(struct rpc_clnt *clnt)  EXPORT_SYMBOL_GPL(rpc_max_payload);  /** + * rpc_get_timeout - Get timeout for transport in units of HZ + * @clnt: RPC client to query + */ +unsigned long rpc_get_timeout(struct rpc_clnt *clnt) +{ +	unsigned long ret; + +	rcu_read_lock(); +	ret = rcu_dereference(clnt->cl_xprt)->timeout->to_initval; +	rcu_read_unlock(); +	return ret; +} +EXPORT_SYMBOL_GPL(rpc_get_timeout); + +/**   * rpc_force_rebind - force transport to check that remote port is unchanged   * @clnt: client to rebind   * diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 846c34fdee9..b7478d5e7ff 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -487,13 +487,17 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);   * xprt_wait_for_buffer_space - wait for transport output buffer to clear   * @task: task to be put to sleep   * @action: function pointer to be executed after wait + * + * Note that we only set the timer for the case of RPC_IS_SOFT(), since + * we don't in general want to force a socket disconnection due to + * an incomplete RPC call transmission.   */  void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)  {  	struct rpc_rqst *req = task->tk_rqstp;  	struct rpc_xprt *xprt = req->rq_xprt; -	task->tk_timeout = req->rq_timeout; +	task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0;  	rpc_sleep_on(&xprt->pending, task, action);  }  EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);  |