diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-02 19:46:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-02 19:46:07 -0500 |
commit | 8d05b3771da8775799673212b57d62f57c70d68a (patch) | |
tree | ebce0455032cec54428227022c92a480fa726da0 /fs | |
parent | b695188dd39162a1a6bff11fdbcc4c0b65b933ab (diff) | |
parent | 512e4b291c0e97af24619a91f3e8963697da00d8 (diff) |
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
Diffstat (limited to 'fs')
-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 |
7 files changed, 55 insertions, 23 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b586fe9af475..1f941674b089 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -237,6 +237,8 @@ nfs_find_actor(struct inode *inode, void *opaque) | |||
237 | 237 | ||
238 | if (NFS_FILEID(inode) != fattr->fileid) | 238 | if (NFS_FILEID(inode) != fattr->fileid) |
239 | return 0; | 239 | return 0; |
240 | if ((S_IFMT & inode->i_mode) != (S_IFMT & fattr->mode)) | ||
241 | return 0; | ||
240 | if (nfs_compare_fh(NFS_FH(inode), fh)) | 242 | if (nfs_compare_fh(NFS_FH(inode), fh)) |
241 | return 0; | 243 | return 0; |
242 | if (is_bad_inode(inode) || NFS_STALE(inode)) | 244 | if (is_bad_inode(inode) || NFS_STALE(inode)) |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 194c48410336..49eeb044c109 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) | |||
99 | 99 | ||
100 | task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode, | 100 | task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode, |
101 | &hdr->pages, | 101 | &hdr->pages, |
102 | hdr->completion_ops); | 102 | hdr->completion_ops, |
103 | hdr->dreq); | ||
103 | } | 104 | } |
104 | } | 105 | } |
105 | 106 | ||
@@ -119,7 +120,8 @@ static void filelayout_reset_read(struct nfs_read_data *data) | |||
119 | 120 | ||
120 | task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode, | 121 | task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode, |
121 | &hdr->pages, | 122 | &hdr->pages, |
122 | hdr->completion_ops); | 123 | hdr->completion_ops, |
124 | hdr->dreq); | ||
123 | } | 125 | } |
124 | } | 126 | } |
125 | 127 | ||
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 8c07241fe52b..b8da95548d3d 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
@@ -36,7 +36,7 @@ | |||
36 | * Default data server connection timeout and retrans vaules. | 36 | * Default data server connection timeout and retrans vaules. |
37 | * Set by module paramters dataserver_timeo and dataserver_retrans. | 37 | * Set by module paramters dataserver_timeo and dataserver_retrans. |
38 | */ | 38 | */ |
39 | #define NFS4_DEF_DS_TIMEO 60 | 39 | #define NFS4_DEF_DS_TIMEO 600 /* in tenths of a second */ |
40 | #define NFS4_DEF_DS_RETRANS 5 | 40 | #define NFS4_DEF_DS_RETRANS 5 |
41 | 41 | ||
42 | /* | 42 | /* |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index eae83bf96c6d..b2671cb0f901 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -93,6 +93,8 @@ static int nfs4_map_errors(int err) | |||
93 | return err; | 93 | return err; |
94 | switch (err) { | 94 | switch (err) { |
95 | case -NFS4ERR_RESOURCE: | 95 | case -NFS4ERR_RESOURCE: |
96 | case -NFS4ERR_LAYOUTTRYLATER: | ||
97 | case -NFS4ERR_RECALLCONFLICT: | ||
96 | return -EREMOTEIO; | 98 | return -EREMOTEIO; |
97 | case -NFS4ERR_WRONGSEC: | 99 | case -NFS4ERR_WRONGSEC: |
98 | return -EPERM; | 100 | return -EPERM; |
@@ -1158,6 +1160,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | |||
1158 | data->o_arg.fmode); | 1160 | data->o_arg.fmode); |
1159 | iput(inode); | 1161 | iput(inode); |
1160 | out: | 1162 | out: |
1163 | nfs_release_seqid(data->o_arg.seqid); | ||
1161 | return state; | 1164 | return state; |
1162 | err_put_inode: | 1165 | err_put_inode: |
1163 | iput(inode); | 1166 | iput(inode); |
@@ -6045,6 +6048,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
6045 | struct nfs_server *server = NFS_SERVER(inode); | 6048 | struct nfs_server *server = NFS_SERVER(inode); |
6046 | struct pnfs_layout_hdr *lo; | 6049 | struct pnfs_layout_hdr *lo; |
6047 | struct nfs4_state *state = NULL; | 6050 | struct nfs4_state *state = NULL; |
6051 | unsigned long timeo, giveup; | ||
6048 | 6052 | ||
6049 | dprintk("--> %s\n", __func__); | 6053 | dprintk("--> %s\n", __func__); |
6050 | 6054 | ||
@@ -6056,7 +6060,10 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
6056 | goto out; | 6060 | goto out; |
6057 | case -NFS4ERR_LAYOUTTRYLATER: | 6061 | case -NFS4ERR_LAYOUTTRYLATER: |
6058 | case -NFS4ERR_RECALLCONFLICT: | 6062 | case -NFS4ERR_RECALLCONFLICT: |
6059 | task->tk_status = -NFS4ERR_DELAY; | 6063 | timeo = rpc_get_timeout(task->tk_client); |
6064 | giveup = lgp->args.timestamp + timeo; | ||
6065 | if (time_after(giveup, jiffies)) | ||
6066 | task->tk_status = -NFS4ERR_DELAY; | ||
6060 | break; | 6067 | break; |
6061 | case -NFS4ERR_EXPIRED: | 6068 | case -NFS4ERR_EXPIRED: |
6062 | case -NFS4ERR_BAD_STATEID: | 6069 | case -NFS4ERR_BAD_STATEID: |
@@ -6129,11 +6136,13 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) | |||
6129 | static void nfs4_layoutget_release(void *calldata) | 6136 | static void nfs4_layoutget_release(void *calldata) |
6130 | { | 6137 | { |
6131 | struct nfs4_layoutget *lgp = calldata; | 6138 | struct nfs4_layoutget *lgp = calldata; |
6132 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | 6139 | struct inode *inode = lgp->args.inode; |
6140 | struct nfs_server *server = NFS_SERVER(inode); | ||
6133 | size_t max_pages = max_response_pages(server); | 6141 | size_t max_pages = max_response_pages(server); |
6134 | 6142 | ||
6135 | dprintk("--> %s\n", __func__); | 6143 | dprintk("--> %s\n", __func__); |
6136 | nfs4_free_pages(lgp->args.layout.pages, max_pages); | 6144 | nfs4_free_pages(lgp->args.layout.pages, max_pages); |
6145 | pnfs_put_layout_hdr(NFS_I(inode)->layout); | ||
6137 | put_nfs_open_context(lgp->args.ctx); | 6146 | put_nfs_open_context(lgp->args.ctx); |
6138 | kfree(calldata); | 6147 | kfree(calldata); |
6139 | dprintk("<-- %s\n", __func__); | 6148 | dprintk("<-- %s\n", __func__); |
@@ -6148,7 +6157,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { | |||
6148 | struct pnfs_layout_segment * | 6157 | struct pnfs_layout_segment * |
6149 | nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) | 6158 | nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) |
6150 | { | 6159 | { |
6151 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | 6160 | struct inode *inode = lgp->args.inode; |
6161 | struct nfs_server *server = NFS_SERVER(inode); | ||
6152 | size_t max_pages = max_response_pages(server); | 6162 | size_t max_pages = max_response_pages(server); |
6153 | struct rpc_task *task; | 6163 | struct rpc_task *task; |
6154 | struct rpc_message msg = { | 6164 | struct rpc_message msg = { |
@@ -6174,10 +6184,15 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) | |||
6174 | return ERR_PTR(-ENOMEM); | 6184 | return ERR_PTR(-ENOMEM); |
6175 | } | 6185 | } |
6176 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; | 6186 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; |
6187 | lgp->args.timestamp = jiffies; | ||
6177 | 6188 | ||
6178 | lgp->res.layoutp = &lgp->args.layout; | 6189 | lgp->res.layoutp = &lgp->args.layout; |
6179 | lgp->res.seq_res.sr_slot = NULL; | 6190 | lgp->res.seq_res.sr_slot = NULL; |
6180 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); | 6191 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); |
6192 | |||
6193 | /* nfs4_layoutget_release calls pnfs_put_layout_hdr */ | ||
6194 | pnfs_get_layout_hdr(NFS_I(inode)->layout); | ||
6195 | |||
6181 | task = rpc_run_task(&task_setup_data); | 6196 | task = rpc_run_task(&task_setup_data); |
6182 | if (IS_ERR(task)) | 6197 | if (IS_ERR(task)) |
6183 | return ERR_CAST(task); | 6198 | return ERR_CAST(task); |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 6be70f622b62..48ac5aad6258 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1181,7 +1181,7 @@ pnfs_update_layout(struct inode *ino, | |||
1181 | struct nfs_client *clp = server->nfs_client; | 1181 | struct nfs_client *clp = server->nfs_client; |
1182 | struct pnfs_layout_hdr *lo; | 1182 | struct pnfs_layout_hdr *lo; |
1183 | struct pnfs_layout_segment *lseg = NULL; | 1183 | struct pnfs_layout_segment *lseg = NULL; |
1184 | bool first = false; | 1184 | bool first; |
1185 | 1185 | ||
1186 | if (!pnfs_enabled_sb(NFS_SERVER(ino))) | 1186 | if (!pnfs_enabled_sb(NFS_SERVER(ino))) |
1187 | goto out; | 1187 | goto out; |
@@ -1215,10 +1215,9 @@ pnfs_update_layout(struct inode *ino, | |||
1215 | goto out_unlock; | 1215 | goto out_unlock; |
1216 | atomic_inc(&lo->plh_outstanding); | 1216 | atomic_inc(&lo->plh_outstanding); |
1217 | 1217 | ||
1218 | if (list_empty(&lo->plh_segs)) | 1218 | first = list_empty(&lo->plh_layouts) ? true : false; |
1219 | first = true; | ||
1220 | |||
1221 | spin_unlock(&ino->i_lock); | 1219 | spin_unlock(&ino->i_lock); |
1220 | |||
1222 | if (first) { | 1221 | if (first) { |
1223 | /* The lo must be on the clp list if there is any | 1222 | /* The lo must be on the clp list if there is any |
1224 | * chance of a CB_LAYOUTRECALL(FILE) coming in. | 1223 | * chance of a CB_LAYOUTRECALL(FILE) coming in. |
@@ -1422,13 +1421,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); | |||
1422 | 1421 | ||
1423 | int pnfs_write_done_resend_to_mds(struct inode *inode, | 1422 | int pnfs_write_done_resend_to_mds(struct inode *inode, |
1424 | struct list_head *head, | 1423 | struct list_head *head, |
1425 | const struct nfs_pgio_completion_ops *compl_ops) | 1424 | const struct nfs_pgio_completion_ops *compl_ops, |
1425 | struct nfs_direct_req *dreq) | ||
1426 | { | 1426 | { |
1427 | struct nfs_pageio_descriptor pgio; | 1427 | struct nfs_pageio_descriptor pgio; |
1428 | LIST_HEAD(failed); | 1428 | LIST_HEAD(failed); |
1429 | 1429 | ||
1430 | /* Resend all requests through the MDS */ | 1430 | /* Resend all requests through the MDS */ |
1431 | nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); | 1431 | nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); |
1432 | pgio.pg_dreq = dreq; | ||
1432 | while (!list_empty(head)) { | 1433 | while (!list_empty(head)) { |
1433 | struct nfs_page *req = nfs_list_entry(head->next); | 1434 | struct nfs_page *req = nfs_list_entry(head->next); |
1434 | 1435 | ||
@@ -1463,7 +1464,8 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) | |||
1463 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) | 1464 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |
1464 | data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, | 1465 | data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, |
1465 | &hdr->pages, | 1466 | &hdr->pages, |
1466 | hdr->completion_ops); | 1467 | hdr->completion_ops, |
1468 | hdr->dreq); | ||
1467 | } | 1469 | } |
1468 | 1470 | ||
1469 | /* | 1471 | /* |
@@ -1578,13 +1580,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); | |||
1578 | 1580 | ||
1579 | int pnfs_read_done_resend_to_mds(struct inode *inode, | 1581 | int pnfs_read_done_resend_to_mds(struct inode *inode, |
1580 | struct list_head *head, | 1582 | struct list_head *head, |
1581 | const struct nfs_pgio_completion_ops *compl_ops) | 1583 | const struct nfs_pgio_completion_ops *compl_ops, |
1584 | struct nfs_direct_req *dreq) | ||
1582 | { | 1585 | { |
1583 | struct nfs_pageio_descriptor pgio; | 1586 | struct nfs_pageio_descriptor pgio; |
1584 | LIST_HEAD(failed); | 1587 | LIST_HEAD(failed); |
1585 | 1588 | ||
1586 | /* Resend all requests through the MDS */ | 1589 | /* Resend all requests through the MDS */ |
1587 | nfs_pageio_init_read(&pgio, inode, compl_ops); | 1590 | nfs_pageio_init_read(&pgio, inode, compl_ops); |
1591 | pgio.pg_dreq = dreq; | ||
1588 | while (!list_empty(head)) { | 1592 | while (!list_empty(head)) { |
1589 | struct nfs_page *req = nfs_list_entry(head->next); | 1593 | struct nfs_page *req = nfs_list_entry(head->next); |
1590 | 1594 | ||
@@ -1615,7 +1619,8 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) | |||
1615 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) | 1619 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |
1616 | data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, | 1620 | data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, |
1617 | &hdr->pages, | 1621 | &hdr->pages, |
1618 | hdr->completion_ops); | 1622 | hdr->completion_ops, |
1623 | hdr->dreq); | ||
1619 | } | 1624 | } |
1620 | 1625 | ||
1621 | /* | 1626 | /* |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 97cb358bb882..94ba80417748 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, | |||
230 | 230 | ||
231 | void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); | 231 | void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); |
232 | int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, | 232 | int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, |
233 | const struct nfs_pgio_completion_ops *compl_ops); | 233 | const struct nfs_pgio_completion_ops *compl_ops, |
234 | struct nfs_direct_req *dreq); | ||
234 | int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, | 235 | int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, |
235 | const struct nfs_pgio_completion_ops *compl_ops); | 236 | const struct nfs_pgio_completion_ops *compl_ops, |
237 | struct nfs_direct_req *dreq); | ||
236 | struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); | 238 | struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); |
237 | 239 | ||
238 | /* nfs4_deviceid_flags */ | 240 | /* nfs4_deviceid_flags */ |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index d26a32f5b53b..1f1f38f0c5d5 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) | |||
335 | struct inode *old_dir = data->old_dir; | 335 | struct inode *old_dir = data->old_dir; |
336 | struct inode *new_dir = data->new_dir; | 336 | struct inode *new_dir = data->new_dir; |
337 | struct dentry *old_dentry = data->old_dentry; | 337 | struct dentry *old_dentry = data->old_dentry; |
338 | struct dentry *new_dentry = data->new_dentry; | ||
339 | 338 | ||
340 | if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) { | 339 | if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) { |
341 | rpc_restart_call_prepare(task); | 340 | rpc_restart_call_prepare(task); |
342 | return; | 341 | return; |
343 | } | 342 | } |
344 | 343 | ||
345 | if (task->tk_status != 0) { | 344 | if (task->tk_status != 0) |
346 | nfs_cancel_async_unlink(old_dentry); | 345 | nfs_cancel_async_unlink(old_dentry); |
347 | return; | ||
348 | } | ||
349 | |||
350 | d_drop(old_dentry); | ||
351 | d_drop(new_dentry); | ||
352 | } | 346 | } |
353 | 347 | ||
354 | /** | 348 | /** |
@@ -549,6 +543,18 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
549 | error = rpc_wait_for_completion_task(task); | 543 | error = rpc_wait_for_completion_task(task); |
550 | if (error == 0) | 544 | if (error == 0) |
551 | error = task->tk_status; | 545 | error = task->tk_status; |
546 | switch (error) { | ||
547 | case 0: | ||
548 | /* The rename succeeded */ | ||
549 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
550 | d_move(dentry, sdentry); | ||
551 | break; | ||
552 | case -ERESTARTSYS: | ||
553 | /* The result of the rename is unknown. Play it safe by | ||
554 | * forcing a new lookup */ | ||
555 | d_drop(dentry); | ||
556 | d_drop(sdentry); | ||
557 | } | ||
552 | rpc_put_task(task); | 558 | rpc_put_task(task); |
553 | out_dput: | 559 | out_dput: |
554 | dput(sdentry); | 560 | dput(sdentry); |