Commit 8d05b377 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.9-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "We've just concluded another Connectathon interoperability testing
  week, and so here are the fixes for the bugs that were discovered:

   - Don't allow NFS silly-renamed files to be deleted
   - Don't start the retransmission timer when out of socket space
   - Fix a couple of pnfs-related Oopses.
   - Fix one more NFSv4 state recovery deadlock
   - Don't loop forever when LAYOUTGET returns NFS4ERR_LAYOUTTRYLATER"

* tag 'nfs-for-3.9-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  SUNRPC: One line comment fix
  NFSv4.1: LAYOUTGET EDELAY loops timeout to the MDS
  SUNRPC: add call to get configured timeout
  PNFS: set the default DS timeout to 60 seconds
  NFSv4: Fix another open/open_recovery deadlock
  nfs: don't allow nfs_find_actor to match inodes of the wrong type
  NFSv4.1: Hold reference to layout hdr in layoutget
  pnfs: fix resend_to_mds for directio
  SUNRPC: Don't start the retransmission timer when out of socket space
  NFS: Don't allow NFS silly-renamed files to be deleted, no signal
parents b695188d 512e4b29
...@@ -237,6 +237,8 @@ nfs_find_actor(struct inode *inode, void *opaque) ...@@ -237,6 +237,8 @@ nfs_find_actor(struct inode *inode, void *opaque)
if (NFS_FILEID(inode) != fattr->fileid) if (NFS_FILEID(inode) != fattr->fileid)
return 0; return 0;
if ((S_IFMT & inode->i_mode) != (S_IFMT & fattr->mode))
return 0;
if (nfs_compare_fh(NFS_FH(inode), fh)) if (nfs_compare_fh(NFS_FH(inode), fh))
return 0; return 0;
if (is_bad_inode(inode) || NFS_STALE(inode)) if (is_bad_inode(inode) || NFS_STALE(inode))
......
...@@ -99,7 +99,8 @@ static void filelayout_reset_write(struct nfs_write_data *data) ...@@ -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, task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode,
&hdr->pages, &hdr->pages,
hdr->completion_ops); hdr->completion_ops,
hdr->dreq);
} }
} }
...@@ -119,7 +120,8 @@ static void filelayout_reset_read(struct nfs_read_data *data) ...@@ -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, task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode,
&hdr->pages, &hdr->pages,
hdr->completion_ops); hdr->completion_ops,
hdr->dreq);
} }
} }
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* Default data server connection timeout and retrans vaules. * Default data server connection timeout and retrans vaules.
* Set by module paramters dataserver_timeo and dataserver_retrans. * 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 #define NFS4_DEF_DS_RETRANS 5
/* /*
......
...@@ -93,6 +93,8 @@ static int nfs4_map_errors(int err) ...@@ -93,6 +93,8 @@ static int nfs4_map_errors(int err)
return err; return err;
switch (err) { switch (err) {
case -NFS4ERR_RESOURCE: case -NFS4ERR_RESOURCE:
case -NFS4ERR_LAYOUTTRYLATER:
case -NFS4ERR_RECALLCONFLICT:
return -EREMOTEIO; return -EREMOTEIO;
case -NFS4ERR_WRONGSEC: case -NFS4ERR_WRONGSEC:
return -EPERM; return -EPERM;
...@@ -1158,6 +1160,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) ...@@ -1158,6 +1160,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
data->o_arg.fmode); data->o_arg.fmode);
iput(inode); iput(inode);
out: out:
nfs_release_seqid(data->o_arg.seqid);
return state; return state;
err_put_inode: err_put_inode:
iput(inode); iput(inode);
...@@ -6045,6 +6048,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) ...@@ -6045,6 +6048,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
struct nfs4_state *state = NULL; struct nfs4_state *state = NULL;
unsigned long timeo, giveup;
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
...@@ -6056,6 +6060,9 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) ...@@ -6056,6 +6060,9 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
goto out; goto out;
case -NFS4ERR_LAYOUTTRYLATER: case -NFS4ERR_LAYOUTTRYLATER:
case -NFS4ERR_RECALLCONFLICT: case -NFS4ERR_RECALLCONFLICT:
timeo = rpc_get_timeout(task->tk_client);
giveup = lgp->args.timestamp + timeo;
if (time_after(giveup, jiffies))
task->tk_status = -NFS4ERR_DELAY; task->tk_status = -NFS4ERR_DELAY;
break; break;
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
...@@ -6129,11 +6136,13 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) ...@@ -6129,11 +6136,13 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
static void nfs4_layoutget_release(void *calldata) static void nfs4_layoutget_release(void *calldata)
{ {
struct nfs4_layoutget *lgp = 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); size_t max_pages = max_response_pages(server);
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
nfs4_free_pages(lgp->args.layout.pages, max_pages); nfs4_free_pages(lgp->args.layout.pages, max_pages);
pnfs_put_layout_hdr(NFS_I(inode)->layout);
put_nfs_open_context(lgp->args.ctx); put_nfs_open_context(lgp->args.ctx);
kfree(calldata); kfree(calldata);
dprintk("<-- %s\n", __func__); dprintk("<-- %s\n", __func__);
...@@ -6148,7 +6157,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { ...@@ -6148,7 +6157,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
struct pnfs_layout_segment * struct pnfs_layout_segment *
nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) 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); size_t max_pages = max_response_pages(server);
struct rpc_task *task; struct rpc_task *task;
struct rpc_message msg = { struct rpc_message msg = {
...@@ -6174,10 +6184,15 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) ...@@ -6174,10 +6184,15 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
lgp->args.layout.pglen = max_pages * PAGE_SIZE; lgp->args.layout.pglen = max_pages * PAGE_SIZE;
lgp->args.timestamp = jiffies;
lgp->res.layoutp = &lgp->args.layout; lgp->res.layoutp = &lgp->args.layout;
lgp->res.seq_res.sr_slot = NULL; lgp->res.seq_res.sr_slot = NULL;
nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); 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); task = rpc_run_task(&task_setup_data);
if (IS_ERR(task)) if (IS_ERR(task))
return ERR_CAST(task); return ERR_CAST(task);
......
...@@ -1181,7 +1181,7 @@ pnfs_update_layout(struct inode *ino, ...@@ -1181,7 +1181,7 @@ pnfs_update_layout(struct inode *ino,
struct nfs_client *clp = server->nfs_client; struct nfs_client *clp = server->nfs_client;
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
struct pnfs_layout_segment *lseg = NULL; struct pnfs_layout_segment *lseg = NULL;
bool first = false; bool first;
if (!pnfs_enabled_sb(NFS_SERVER(ino))) if (!pnfs_enabled_sb(NFS_SERVER(ino)))
goto out; goto out;
...@@ -1215,10 +1215,9 @@ pnfs_update_layout(struct inode *ino, ...@@ -1215,10 +1215,9 @@ pnfs_update_layout(struct inode *ino,
goto out_unlock; goto out_unlock;
atomic_inc(&lo->plh_outstanding); atomic_inc(&lo->plh_outstanding);
if (list_empty(&lo->plh_segs)) first = list_empty(&lo->plh_layouts) ? true : false;
first = true;
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
if (first) { if (first) {
/* The lo must be on the clp list if there is any /* The lo must be on the clp list if there is any
* chance of a CB_LAYOUTRECALL(FILE) coming in. * chance of a CB_LAYOUTRECALL(FILE) coming in.
...@@ -1422,13 +1421,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); ...@@ -1422,13 +1421,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
int pnfs_write_done_resend_to_mds(struct inode *inode, int pnfs_write_done_resend_to_mds(struct inode *inode,
struct list_head *head, 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; struct nfs_pageio_descriptor pgio;
LIST_HEAD(failed); LIST_HEAD(failed);
/* Resend all requests through the MDS */ /* Resend all requests through the MDS */
nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops);
pgio.pg_dreq = dreq;
while (!list_empty(head)) { while (!list_empty(head)) {
struct nfs_page *req = nfs_list_entry(head->next); 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) ...@@ -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)) if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode,
&hdr->pages, &hdr->pages,
hdr->completion_ops); hdr->completion_ops,
hdr->dreq);
} }
/* /*
...@@ -1578,13 +1580,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); ...@@ -1578,13 +1580,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);
int pnfs_read_done_resend_to_mds(struct inode *inode, int pnfs_read_done_resend_to_mds(struct inode *inode,
struct list_head *head, 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; struct nfs_pageio_descriptor pgio;
LIST_HEAD(failed); LIST_HEAD(failed);
/* Resend all requests through the MDS */ /* Resend all requests through the MDS */
nfs_pageio_init_read(&pgio, inode, compl_ops); nfs_pageio_init_read(&pgio, inode, compl_ops);
pgio.pg_dreq = dreq;
while (!list_empty(head)) { while (!list_empty(head)) {
struct nfs_page *req = nfs_list_entry(head->next); 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) ...@@ -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)) if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode,
&hdr->pages, &hdr->pages,
hdr->completion_ops); hdr->completion_ops,
hdr->dreq);
} }
/* /*
......
...@@ -230,9 +230,11 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, ...@@ -230,9 +230,11 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp);
int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, 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, 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); struct nfs4_threshold *pnfs_mdsthreshold_alloc(void);
/* nfs4_deviceid_flags */ /* nfs4_deviceid_flags */
......
...@@ -335,20 +335,14 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) ...@@ -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 *old_dir = data->old_dir;
struct inode *new_dir = data->new_dir; struct inode *new_dir = data->new_dir;
struct dentry *old_dentry = data->old_dentry; 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)) { if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
return; return;
} }
if (task->tk_status != 0) { if (task->tk_status != 0)
nfs_cancel_async_unlink(old_dentry); 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) ...@@ -549,6 +543,18 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
error = rpc_wait_for_completion_task(task); error = rpc_wait_for_completion_task(task);
if (error == 0) if (error == 0)
error = task->tk_status; 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); rpc_put_task(task);
out_dput: out_dput:
dput(sdentry); dput(sdentry);
......
...@@ -233,6 +233,7 @@ struct nfs4_layoutget_args { ...@@ -233,6 +233,7 @@ struct nfs4_layoutget_args {
struct inode *inode; struct inode *inode;
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
nfs4_stateid stateid; nfs4_stateid stateid;
unsigned long timestamp;
struct nfs4_layoutdriver_data layout; struct nfs4_layoutdriver_data layout;
}; };
......
...@@ -160,6 +160,7 @@ void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); ...@@ -160,6 +160,7 @@ void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
int rpc_protocol(struct rpc_clnt *); int rpc_protocol(struct rpc_clnt *);
struct net * rpc_net_ns(struct rpc_clnt *); struct net * rpc_net_ns(struct rpc_clnt *);
size_t rpc_max_payload(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 *); void rpc_force_rebind(struct rpc_clnt *);
size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
......
...@@ -1196,6 +1196,21 @@ size_t rpc_max_payload(struct rpc_clnt *clnt) ...@@ -1196,6 +1196,21 @@ size_t rpc_max_payload(struct rpc_clnt *clnt)
} }
EXPORT_SYMBOL_GPL(rpc_max_payload); 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 * rpc_force_rebind - force transport to check that remote port is unchanged
* @clnt: client to rebind * @clnt: client to rebind
......
...@@ -487,13 +487,17 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks); ...@@ -487,13 +487,17 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
* xprt_wait_for_buffer_space - wait for transport output buffer to clear * xprt_wait_for_buffer_space - wait for transport output buffer to clear
* @task: task to be put to sleep * @task: task to be put to sleep
* @action: function pointer to be executed after wait * @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) void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)
{ {
struct rpc_rqst *req = task->tk_rqstp; struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = req->rq_xprt; 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); rpc_sleep_on(&xprt->pending, task, action);
} }
EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space); EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment