diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-25 12:19:58 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-25 12:19:58 -0500 |
| commit | 17c2f540863a6c0faa3f0ede3c785d9427bcaf80 (patch) | |
| tree | 8c90950536b5bbbd63783b1b29b90f7e1907c647 | |
| parent | 4e962ff6e34f44c400c548da0c1e2393053a691e (diff) | |
| parent | bb21ce0ad227b69ec0f83279297ee44232105d96 (diff) | |
Merge tag 'nfs-for-4.20-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
- Fix a NFSv4 state manager deadlock when returning a delegation
- NFSv4.2 copy do not allocate memory under the lock
- flexfiles: Use the correct stateid for IO in the tightly coupled case
* tag 'nfs-for-4.20-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
flexfiles: use per-mirror specified stateid for IO
NFSv4.2 copy do not allocate memory under the lock
NFSv4: Fix a NFSv4 state manager deadlock
| -rw-r--r-- | fs/nfs/callback_proc.c | 22 | ||||
| -rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 21 | ||||
| -rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.h | 4 | ||||
| -rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayoutdev.c | 19 | ||||
| -rw-r--r-- | fs/nfs/nfs42proc.c | 19 | ||||
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 16 |
7 files changed, 66 insertions, 37 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 7b861bbc0b43..315967354954 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
| @@ -686,20 +686,24 @@ __be32 nfs4_callback_offload(void *data, void *dummy, | |||
| 686 | { | 686 | { |
| 687 | struct cb_offloadargs *args = data; | 687 | struct cb_offloadargs *args = data; |
| 688 | struct nfs_server *server; | 688 | struct nfs_server *server; |
| 689 | struct nfs4_copy_state *copy; | 689 | struct nfs4_copy_state *copy, *tmp_copy; |
| 690 | bool found = false; | 690 | bool found = false; |
| 691 | 691 | ||
| 692 | copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); | ||
| 693 | if (!copy) | ||
| 694 | return htonl(NFS4ERR_SERVERFAULT); | ||
| 695 | |||
| 692 | spin_lock(&cps->clp->cl_lock); | 696 | spin_lock(&cps->clp->cl_lock); |
| 693 | rcu_read_lock(); | 697 | rcu_read_lock(); |
| 694 | list_for_each_entry_rcu(server, &cps->clp->cl_superblocks, | 698 | list_for_each_entry_rcu(server, &cps->clp->cl_superblocks, |
| 695 | client_link) { | 699 | client_link) { |
| 696 | list_for_each_entry(copy, &server->ss_copies, copies) { | 700 | list_for_each_entry(tmp_copy, &server->ss_copies, copies) { |
| 697 | if (memcmp(args->coa_stateid.other, | 701 | if (memcmp(args->coa_stateid.other, |
| 698 | copy->stateid.other, | 702 | tmp_copy->stateid.other, |
| 699 | sizeof(args->coa_stateid.other))) | 703 | sizeof(args->coa_stateid.other))) |
| 700 | continue; | 704 | continue; |
| 701 | nfs4_copy_cb_args(copy, args); | 705 | nfs4_copy_cb_args(tmp_copy, args); |
| 702 | complete(©->completion); | 706 | complete(&tmp_copy->completion); |
| 703 | found = true; | 707 | found = true; |
| 704 | goto out; | 708 | goto out; |
| 705 | } | 709 | } |
| @@ -707,15 +711,11 @@ __be32 nfs4_callback_offload(void *data, void *dummy, | |||
| 707 | out: | 711 | out: |
| 708 | rcu_read_unlock(); | 712 | rcu_read_unlock(); |
| 709 | if (!found) { | 713 | if (!found) { |
| 710 | copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); | ||
| 711 | if (!copy) { | ||
| 712 | spin_unlock(&cps->clp->cl_lock); | ||
| 713 | return htonl(NFS4ERR_SERVERFAULT); | ||
| 714 | } | ||
| 715 | memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE); | 714 | memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE); |
| 716 | nfs4_copy_cb_args(copy, args); | 715 | nfs4_copy_cb_args(copy, args); |
| 717 | list_add_tail(©->copies, &cps->clp->pending_cb_stateids); | 716 | list_add_tail(©->copies, &cps->clp->pending_cb_stateids); |
| 718 | } | 717 | } else |
| 718 | kfree(copy); | ||
| 719 | spin_unlock(&cps->clp->cl_lock); | 719 | spin_unlock(&cps->clp->cl_lock); |
| 720 | 720 | ||
| 721 | return 0; | 721 | return 0; |
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 86bcba40ca61..74b36ed883ca 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
| @@ -1361,12 +1361,7 @@ static void ff_layout_read_prepare_v4(struct rpc_task *task, void *data) | |||
| 1361 | task)) | 1361 | task)) |
| 1362 | return; | 1362 | return; |
| 1363 | 1363 | ||
| 1364 | if (ff_layout_read_prepare_common(task, hdr)) | 1364 | ff_layout_read_prepare_common(task, hdr); |
| 1365 | return; | ||
| 1366 | |||
| 1367 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, | ||
| 1368 | hdr->args.lock_context, FMODE_READ) == -EIO) | ||
| 1369 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | ||
| 1370 | } | 1365 | } |
| 1371 | 1366 | ||
| 1372 | static void ff_layout_read_call_done(struct rpc_task *task, void *data) | 1367 | static void ff_layout_read_call_done(struct rpc_task *task, void *data) |
| @@ -1542,12 +1537,7 @@ static void ff_layout_write_prepare_v4(struct rpc_task *task, void *data) | |||
| 1542 | task)) | 1537 | task)) |
| 1543 | return; | 1538 | return; |
| 1544 | 1539 | ||
| 1545 | if (ff_layout_write_prepare_common(task, hdr)) | 1540 | ff_layout_write_prepare_common(task, hdr); |
| 1546 | return; | ||
| 1547 | |||
| 1548 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, | ||
| 1549 | hdr->args.lock_context, FMODE_WRITE) == -EIO) | ||
| 1550 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | ||
| 1551 | } | 1541 | } |
| 1552 | 1542 | ||
| 1553 | static void ff_layout_write_call_done(struct rpc_task *task, void *data) | 1543 | static void ff_layout_write_call_done(struct rpc_task *task, void *data) |
| @@ -1742,6 +1732,10 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr) | |||
| 1742 | fh = nfs4_ff_layout_select_ds_fh(lseg, idx); | 1732 | fh = nfs4_ff_layout_select_ds_fh(lseg, idx); |
| 1743 | if (fh) | 1733 | if (fh) |
| 1744 | hdr->args.fh = fh; | 1734 | hdr->args.fh = fh; |
| 1735 | |||
| 1736 | if (!nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid)) | ||
| 1737 | goto out_failed; | ||
| 1738 | |||
| 1745 | /* | 1739 | /* |
| 1746 | * Note that if we ever decide to split across DSes, | 1740 | * Note that if we ever decide to split across DSes, |
| 1747 | * then we may need to handle dense-like offsets. | 1741 | * then we may need to handle dense-like offsets. |
| @@ -1804,6 +1798,9 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync) | |||
| 1804 | if (fh) | 1798 | if (fh) |
| 1805 | hdr->args.fh = fh; | 1799 | hdr->args.fh = fh; |
| 1806 | 1800 | ||
| 1801 | if (!nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid)) | ||
| 1802 | goto out_failed; | ||
| 1803 | |||
| 1807 | /* | 1804 | /* |
| 1808 | * Note that if we ever decide to split across DSes, | 1805 | * Note that if we ever decide to split across DSes, |
| 1809 | * then we may need to handle dense-like offsets. | 1806 | * then we may need to handle dense-like offsets. |
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index 411798346e48..de50a342d5a5 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h | |||
| @@ -215,6 +215,10 @@ unsigned int ff_layout_fetch_ds_ioerr(struct pnfs_layout_hdr *lo, | |||
| 215 | unsigned int maxnum); | 215 | unsigned int maxnum); |
| 216 | struct nfs_fh * | 216 | struct nfs_fh * |
| 217 | nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx); | 217 | nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx); |
| 218 | int | ||
| 219 | nfs4_ff_layout_select_ds_stateid(struct pnfs_layout_segment *lseg, | ||
| 220 | u32 mirror_idx, | ||
| 221 | nfs4_stateid *stateid); | ||
| 218 | 222 | ||
| 219 | struct nfs4_pnfs_ds * | 223 | struct nfs4_pnfs_ds * |
| 220 | nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, | 224 | nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, |
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index 74d8d5352438..d23347389626 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c | |||
| @@ -370,6 +370,25 @@ out: | |||
| 370 | return fh; | 370 | return fh; |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | int | ||
| 374 | nfs4_ff_layout_select_ds_stateid(struct pnfs_layout_segment *lseg, | ||
| 375 | u32 mirror_idx, | ||
| 376 | nfs4_stateid *stateid) | ||
| 377 | { | ||
| 378 | struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, mirror_idx); | ||
| 379 | |||
| 380 | if (!ff_layout_mirror_valid(lseg, mirror, false)) { | ||
| 381 | pr_err_ratelimited("NFS: %s: No data server for mirror offset index %d\n", | ||
| 382 | __func__, mirror_idx); | ||
| 383 | goto out; | ||
| 384 | } | ||
| 385 | |||
| 386 | nfs4_stateid_copy(stateid, &mirror->stateid); | ||
| 387 | return 1; | ||
| 388 | out: | ||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 373 | /** | 392 | /** |
| 374 | * nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call | 393 | * nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call |
| 375 | * @lseg: the layout segment we're operating on | 394 | * @lseg: the layout segment we're operating on |
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index ac5b784a1de0..fed06fd9998d 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c | |||
| @@ -137,31 +137,32 @@ static int handle_async_copy(struct nfs42_copy_res *res, | |||
| 137 | struct file *dst, | 137 | struct file *dst, |
| 138 | nfs4_stateid *src_stateid) | 138 | nfs4_stateid *src_stateid) |
| 139 | { | 139 | { |
| 140 | struct nfs4_copy_state *copy; | 140 | struct nfs4_copy_state *copy, *tmp_copy; |
| 141 | int status = NFS4_OK; | 141 | int status = NFS4_OK; |
| 142 | bool found_pending = false; | 142 | bool found_pending = false; |
| 143 | struct nfs_open_context *ctx = nfs_file_open_context(dst); | 143 | struct nfs_open_context *ctx = nfs_file_open_context(dst); |
| 144 | 144 | ||
| 145 | copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); | ||
| 146 | if (!copy) | ||
| 147 | return -ENOMEM; | ||
| 148 | |||
| 145 | spin_lock(&server->nfs_client->cl_lock); | 149 | spin_lock(&server->nfs_client->cl_lock); |
| 146 | list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids, | 150 | list_for_each_entry(tmp_copy, &server->nfs_client->pending_cb_stateids, |
| 147 | copies) { | 151 | copies) { |
| 148 | if (memcmp(&res->write_res.stateid, ©->stateid, | 152 | if (memcmp(&res->write_res.stateid, &tmp_copy->stateid, |
| 149 | NFS4_STATEID_SIZE)) | 153 | NFS4_STATEID_SIZE)) |
| 150 | continue; | 154 | continue; |
| 151 | found_pending = true; | 155 | found_pending = true; |
| 152 | list_del(©->copies); | 156 | list_del(&tmp_copy->copies); |
| 153 | break; | 157 | break; |
| 154 | } | 158 | } |
| 155 | if (found_pending) { | 159 | if (found_pending) { |
| 156 | spin_unlock(&server->nfs_client->cl_lock); | 160 | spin_unlock(&server->nfs_client->cl_lock); |
| 161 | kfree(copy); | ||
| 162 | copy = tmp_copy; | ||
| 157 | goto out; | 163 | goto out; |
| 158 | } | 164 | } |
| 159 | 165 | ||
| 160 | copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); | ||
| 161 | if (!copy) { | ||
| 162 | spin_unlock(&server->nfs_client->cl_lock); | ||
| 163 | return -ENOMEM; | ||
| 164 | } | ||
| 165 | memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE); | 166 | memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE); |
| 166 | init_completion(©->completion); | 167 | init_completion(©->completion); |
| 167 | copy->parent_state = ctx->state; | 168 | copy->parent_state = ctx->state; |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 8d59c9655ec4..1b994b527518 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -41,6 +41,8 @@ enum nfs4_client_state { | |||
| 41 | NFS4CLNT_MOVED, | 41 | NFS4CLNT_MOVED, |
| 42 | NFS4CLNT_LEASE_MOVED, | 42 | NFS4CLNT_LEASE_MOVED, |
| 43 | NFS4CLNT_DELEGATION_EXPIRED, | 43 | NFS4CLNT_DELEGATION_EXPIRED, |
| 44 | NFS4CLNT_RUN_MANAGER, | ||
| 45 | NFS4CLNT_DELEGRETURN_RUNNING, | ||
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 46 | #define NFS4_RENEW_TIMEOUT 0x01 | 48 | #define NFS4_RENEW_TIMEOUT 0x01 |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index ffea57885394..d8decf2ec48f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -1210,6 +1210,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp) | |||
| 1210 | struct task_struct *task; | 1210 | struct task_struct *task; |
| 1211 | char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1]; | 1211 | char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1]; |
| 1212 | 1212 | ||
| 1213 | set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state); | ||
| 1213 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | 1214 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) |
| 1214 | return; | 1215 | return; |
| 1215 | __module_get(THIS_MODULE); | 1216 | __module_get(THIS_MODULE); |
| @@ -2503,6 +2504,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 2503 | 2504 | ||
| 2504 | /* Ensure exclusive access to NFSv4 state */ | 2505 | /* Ensure exclusive access to NFSv4 state */ |
| 2505 | do { | 2506 | do { |
| 2507 | clear_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state); | ||
| 2506 | if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) { | 2508 | if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) { |
| 2507 | section = "purge state"; | 2509 | section = "purge state"; |
| 2508 | status = nfs4_purge_lease(clp); | 2510 | status = nfs4_purge_lease(clp); |
| @@ -2593,14 +2595,18 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 2593 | } | 2595 | } |
| 2594 | 2596 | ||
| 2595 | nfs4_end_drain_session(clp); | 2597 | nfs4_end_drain_session(clp); |
| 2596 | if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) { | 2598 | nfs4_clear_state_manager_bit(clp); |
| 2597 | nfs_client_return_marked_delegations(clp); | 2599 | |
| 2598 | continue; | 2600 | if (!test_and_set_bit(NFS4CLNT_DELEGRETURN_RUNNING, &clp->cl_state)) { |
| 2601 | if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) { | ||
| 2602 | nfs_client_return_marked_delegations(clp); | ||
| 2603 | set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state); | ||
| 2604 | } | ||
| 2605 | clear_bit(NFS4CLNT_DELEGRETURN_RUNNING, &clp->cl_state); | ||
| 2599 | } | 2606 | } |
| 2600 | 2607 | ||
| 2601 | nfs4_clear_state_manager_bit(clp); | ||
| 2602 | /* Did we race with an attempt to give us more work? */ | 2608 | /* Did we race with an attempt to give us more work? */ |
| 2603 | if (clp->cl_state == 0) | 2609 | if (!test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state)) |
| 2604 | return; | 2610 | return; |
| 2605 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | 2611 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) |
| 2606 | return; | 2612 | return; |
