diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-15 17:15:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-15 17:15:16 -0500 |
commit | 1afcb6ed0d34c5794a51fe325076f006c8babaf4 (patch) | |
tree | a39a9b36d96dca051c0506cfde57269a1cd1a31c | |
parent | 56c381f93d57b88a3e667a2f55137947315c17e2 (diff) | |
parent | b3ecba096729f521312d1863ad22530695527aed (diff) |
Merge tag 'nfs-for-3.18-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights include:
- stable patches to fix NFSv4.x delegation reclaim error paths
- fix a bug whereby we were advertising NFSv4.1 but using NFSv4.2
features
- fix a use-after-free problem with pNFS block layouts
- fix a memory leak in the pNFS files O_DIRECT code
- replace an intrusive and Oops-prone performance fix in the NFSv4
atomic open code with a safer one-line version and revert the two
original patches"
* tag 'nfs-for-3.18-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
sunrpc: fix sleeping under rcu_read_lock in gss_stringify_acceptor
NFS: Don't try to reclaim delegation open state if recovery failed
NFSv4: Ensure that we call FREE_STATEID when NFSv4.x stateids are revoked
NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return
NFSv4.1: nfs41_clear_delegation_stateid shouldn't trust NFS_DELEGATED_STATE
NFSv4: Ensure that we remove NFSv4.0 delegations when state has expired
NFS: SEEK is an NFS v4.2 feature
nfs: Fix use of uninitialized variable in nfs_getattr()
nfs: Remove bogus assignment
nfs: remove spurious WARN_ON_ONCE in write path
pnfs/blocklayout: serialize GETDEVICEINFO calls
nfs: fix pnfs direct write memory leak
Revert "NFS: nfs4_do_open should add negative results to the dcache."
Revert "NFS: remove BUG possibility in nfs4_open_and_get_state"
NFSv4: Ensure nfs_atomic_open set the dentry verifier on ENOENT
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 2 | ||||
-rw-r--r-- | fs/nfs/blocklayout/rpc_pipefs.c | 14 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 25 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 1 | ||||
-rw-r--r-- | fs/nfs/dir.c | 1 | ||||
-rw-r--r-- | fs/nfs/direct.c | 1 | ||||
-rw-r--r-- | fs/nfs/filelayout/filelayout.c | 3 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/netns.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 95 | ||||
-rw-r--r-- | fs/nfs/write.c | 2 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 11 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 35 |
13 files changed, 124 insertions, 69 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 5228f201d3d5..4f46f7a05289 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -378,7 +378,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) | |||
378 | loff_t offset = header->args.offset; | 378 | loff_t offset = header->args.offset; |
379 | size_t count = header->args.count; | 379 | size_t count = header->args.count; |
380 | struct page **pages = header->args.pages; | 380 | struct page **pages = header->args.pages; |
381 | int pg_index = pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; | 381 | int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; |
382 | unsigned int pg_len; | 382 | unsigned int pg_len; |
383 | struct blk_plug plug; | 383 | struct blk_plug plug; |
384 | int i; | 384 | int i; |
diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c index e966c023b1b7..acbf9ca4018c 100644 --- a/fs/nfs/blocklayout/rpc_pipefs.c +++ b/fs/nfs/blocklayout/rpc_pipefs.c | |||
@@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
65 | 65 | ||
66 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); | 66 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); |
67 | 67 | ||
68 | mutex_lock(&nn->bl_mutex); | ||
68 | bl_pipe_msg.bl_wq = &nn->bl_wq; | 69 | bl_pipe_msg.bl_wq = &nn->bl_wq; |
69 | 70 | ||
70 | b->simple.len += 4; /* single volume */ | 71 | b->simple.len += 4; /* single volume */ |
71 | if (b->simple.len > PAGE_SIZE) | 72 | if (b->simple.len > PAGE_SIZE) |
72 | return -EIO; | 73 | goto out_unlock; |
73 | 74 | ||
74 | memset(msg, 0, sizeof(*msg)); | 75 | memset(msg, 0, sizeof(*msg)); |
75 | msg->len = sizeof(*bl_msg) + b->simple.len; | 76 | msg->len = sizeof(*bl_msg) + b->simple.len; |
76 | msg->data = kzalloc(msg->len, gfp_mask); | 77 | msg->data = kzalloc(msg->len, gfp_mask); |
77 | if (!msg->data) | 78 | if (!msg->data) |
78 | goto out; | 79 | goto out_free_data; |
79 | 80 | ||
80 | bl_msg = msg->data; | 81 | bl_msg = msg->data; |
81 | bl_msg->type = BL_DEVICE_MOUNT, | 82 | bl_msg->type = BL_DEVICE_MOUNT, |
@@ -87,7 +88,7 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
87 | rc = rpc_queue_upcall(nn->bl_device_pipe, msg); | 88 | rc = rpc_queue_upcall(nn->bl_device_pipe, msg); |
88 | if (rc < 0) { | 89 | if (rc < 0) { |
89 | remove_wait_queue(&nn->bl_wq, &wq); | 90 | remove_wait_queue(&nn->bl_wq, &wq); |
90 | goto out; | 91 | goto out_free_data; |
91 | } | 92 | } |
92 | 93 | ||
93 | set_current_state(TASK_UNINTERRUPTIBLE); | 94 | set_current_state(TASK_UNINTERRUPTIBLE); |
@@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
97 | if (reply->status != BL_DEVICE_REQUEST_PROC) { | 98 | if (reply->status != BL_DEVICE_REQUEST_PROC) { |
98 | printk(KERN_WARNING "%s failed to decode device: %d\n", | 99 | printk(KERN_WARNING "%s failed to decode device: %d\n", |
99 | __func__, reply->status); | 100 | __func__, reply->status); |
100 | goto out; | 101 | goto out_free_data; |
101 | } | 102 | } |
102 | 103 | ||
103 | dev = MKDEV(reply->major, reply->minor); | 104 | dev = MKDEV(reply->major, reply->minor); |
104 | out: | 105 | out_free_data: |
105 | kfree(msg->data); | 106 | kfree(msg->data); |
107 | out_unlock: | ||
108 | mutex_unlock(&nn->bl_mutex); | ||
106 | return dev; | 109 | return dev; |
107 | } | 110 | } |
108 | 111 | ||
@@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net) | |||
232 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 235 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
233 | struct dentry *dentry; | 236 | struct dentry *dentry; |
234 | 237 | ||
238 | mutex_init(&nn->bl_mutex); | ||
235 | init_waitqueue_head(&nn->bl_wq); | 239 | init_waitqueue_head(&nn->bl_wq); |
236 | nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); | 240 | nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); |
237 | if (IS_ERR(nn->bl_device_pipe)) | 241 | if (IS_ERR(nn->bl_device_pipe)) |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5853f53db732..7f3f60641344 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -125,6 +125,8 @@ again: | |||
125 | continue; | 125 | continue; |
126 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 126 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
127 | continue; | 127 | continue; |
128 | if (!nfs4_valid_open_stateid(state)) | ||
129 | continue; | ||
128 | if (!nfs4_stateid_match(&state->stateid, stateid)) | 130 | if (!nfs4_stateid_match(&state->stateid, stateid)) |
129 | continue; | 131 | continue; |
130 | get_nfs_open_context(ctx); | 132 | get_nfs_open_context(ctx); |
@@ -193,7 +195,11 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * | |||
193 | { | 195 | { |
194 | int res = 0; | 196 | int res = 0; |
195 | 197 | ||
196 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); | 198 | if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) |
199 | res = nfs4_proc_delegreturn(inode, | ||
200 | delegation->cred, | ||
201 | &delegation->stateid, | ||
202 | issync); | ||
197 | nfs_free_delegation(delegation); | 203 | nfs_free_delegation(delegation); |
198 | return res; | 204 | return res; |
199 | } | 205 | } |
@@ -380,11 +386,13 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation | |||
380 | { | 386 | { |
381 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 387 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
382 | struct nfs_inode *nfsi = NFS_I(inode); | 388 | struct nfs_inode *nfsi = NFS_I(inode); |
383 | int err; | 389 | int err = 0; |
384 | 390 | ||
385 | if (delegation == NULL) | 391 | if (delegation == NULL) |
386 | return 0; | 392 | return 0; |
387 | do { | 393 | do { |
394 | if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) | ||
395 | break; | ||
388 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); | 396 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); |
389 | if (!issync || err != -EAGAIN) | 397 | if (!issync || err != -EAGAIN) |
390 | break; | 398 | break; |
@@ -605,10 +613,23 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl | |||
605 | rcu_read_unlock(); | 613 | rcu_read_unlock(); |
606 | } | 614 | } |
607 | 615 | ||
616 | static void nfs_revoke_delegation(struct inode *inode) | ||
617 | { | ||
618 | struct nfs_delegation *delegation; | ||
619 | rcu_read_lock(); | ||
620 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
621 | if (delegation != NULL) { | ||
622 | set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); | ||
623 | nfs_mark_return_delegation(NFS_SERVER(inode), delegation); | ||
624 | } | ||
625 | rcu_read_unlock(); | ||
626 | } | ||
627 | |||
608 | void nfs_remove_bad_delegation(struct inode *inode) | 628 | void nfs_remove_bad_delegation(struct inode *inode) |
609 | { | 629 | { |
610 | struct nfs_delegation *delegation; | 630 | struct nfs_delegation *delegation; |
611 | 631 | ||
632 | nfs_revoke_delegation(inode); | ||
612 | delegation = nfs_inode_detach_delegation(inode); | 633 | delegation = nfs_inode_detach_delegation(inode); |
613 | if (delegation) { | 634 | if (delegation) { |
614 | nfs_inode_find_state_and_recover(inode, &delegation->stateid); | 635 | nfs_inode_find_state_and_recover(inode, &delegation->stateid); |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 5c1cce39297f..e3c20a3ccc93 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -31,6 +31,7 @@ enum { | |||
31 | NFS_DELEGATION_RETURN_IF_CLOSED, | 31 | NFS_DELEGATION_RETURN_IF_CLOSED, |
32 | NFS_DELEGATION_REFERENCED, | 32 | NFS_DELEGATION_REFERENCED, |
33 | NFS_DELEGATION_RETURNING, | 33 | NFS_DELEGATION_RETURNING, |
34 | NFS_DELEGATION_REVOKED, | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 37 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 06e8cfcbb670..6e62155abf26 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1527,6 +1527,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, | |||
1527 | case -ENOENT: | 1527 | case -ENOENT: |
1528 | d_drop(dentry); | 1528 | d_drop(dentry); |
1529 | d_add(dentry, NULL); | 1529 | d_add(dentry, NULL); |
1530 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1530 | break; | 1531 | break; |
1531 | case -EISDIR: | 1532 | case -EISDIR: |
1532 | case -ENOTDIR: | 1533 | case -ENOTDIR: |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 20cffc830468..10bf07280f4a 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -266,6 +266,7 @@ static void nfs_direct_req_free(struct kref *kref) | |||
266 | { | 266 | { |
267 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); | 267 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); |
268 | 268 | ||
269 | nfs_free_pnfs_ds_cinfo(&dreq->ds_cinfo); | ||
269 | if (dreq->l_ctx != NULL) | 270 | if (dreq->l_ctx != NULL) |
270 | nfs_put_lock_context(dreq->l_ctx); | 271 | nfs_put_lock_context(dreq->l_ctx); |
271 | if (dreq->ctx != NULL) | 272 | if (dreq->ctx != NULL) |
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index 46fab1cb455a..7afb52f6a25a 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c | |||
@@ -145,9 +145,6 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
145 | case -NFS4ERR_DELEG_REVOKED: | 145 | case -NFS4ERR_DELEG_REVOKED: |
146 | case -NFS4ERR_ADMIN_REVOKED: | 146 | case -NFS4ERR_ADMIN_REVOKED: |
147 | case -NFS4ERR_BAD_STATEID: | 147 | case -NFS4ERR_BAD_STATEID: |
148 | if (state == NULL) | ||
149 | break; | ||
150 | nfs_remove_bad_delegation(state->inode); | ||
151 | case -NFS4ERR_OPENMODE: | 148 | case -NFS4ERR_OPENMODE: |
152 | if (state == NULL) | 149 | if (state == NULL) |
153 | break; | 150 | break; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6388a59f2add..00689a8a85e4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -626,7 +626,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
626 | { | 626 | { |
627 | struct inode *inode = dentry->d_inode; | 627 | struct inode *inode = dentry->d_inode; |
628 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; | 628 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; |
629 | int err; | 629 | int err = 0; |
630 | 630 | ||
631 | trace_nfs_getattr_enter(inode); | 631 | trace_nfs_getattr_enter(inode); |
632 | /* Flush out writes to the server in order to update c/mtime. */ | 632 | /* Flush out writes to the server in order to update c/mtime. */ |
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index ef221fb8a183..f0e06e4acbef 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h | |||
@@ -19,6 +19,7 @@ struct nfs_net { | |||
19 | struct rpc_pipe *bl_device_pipe; | 19 | struct rpc_pipe *bl_device_pipe; |
20 | struct bl_dev_msg bl_mount_reply; | 20 | struct bl_dev_msg bl_mount_reply; |
21 | wait_queue_head_t bl_wq; | 21 | wait_queue_head_t bl_wq; |
22 | struct mutex bl_mutex; | ||
22 | struct list_head nfs_client_list; | 23 | struct list_head nfs_client_list; |
23 | struct list_head nfs_volume_list; | 24 | struct list_head nfs_volume_list; |
24 | #if IS_ENABLED(CONFIG_NFS_V4) | 25 | #if IS_ENABLED(CONFIG_NFS_V4) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 405bd95c1f58..69dc20a743f9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -370,11 +370,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
370 | case -NFS4ERR_DELEG_REVOKED: | 370 | case -NFS4ERR_DELEG_REVOKED: |
371 | case -NFS4ERR_ADMIN_REVOKED: | 371 | case -NFS4ERR_ADMIN_REVOKED: |
372 | case -NFS4ERR_BAD_STATEID: | 372 | case -NFS4ERR_BAD_STATEID: |
373 | if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) { | ||
374 | nfs_remove_bad_delegation(inode); | ||
375 | exception->retry = 1; | ||
376 | break; | ||
377 | } | ||
378 | if (state == NULL) | 373 | if (state == NULL) |
379 | break; | 374 | break; |
380 | ret = nfs4_schedule_stateid_recovery(server, state); | 375 | ret = nfs4_schedule_stateid_recovery(server, state); |
@@ -1654,7 +1649,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
1654 | nfs_inode_find_state_and_recover(state->inode, | 1649 | nfs_inode_find_state_and_recover(state->inode, |
1655 | stateid); | 1650 | stateid); |
1656 | nfs4_schedule_stateid_recovery(server, state); | 1651 | nfs4_schedule_stateid_recovery(server, state); |
1657 | return 0; | 1652 | return -EAGAIN; |
1658 | case -NFS4ERR_DELAY: | 1653 | case -NFS4ERR_DELAY: |
1659 | case -NFS4ERR_GRACE: | 1654 | case -NFS4ERR_GRACE: |
1660 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 1655 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
@@ -2109,46 +2104,60 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
2109 | return ret; | 2104 | return ret; |
2110 | } | 2105 | } |
2111 | 2106 | ||
2107 | static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state) | ||
2108 | { | ||
2109 | nfs_remove_bad_delegation(state->inode); | ||
2110 | write_seqlock(&state->seqlock); | ||
2111 | nfs4_stateid_copy(&state->stateid, &state->open_stateid); | ||
2112 | write_sequnlock(&state->seqlock); | ||
2113 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2114 | } | ||
2115 | |||
2116 | static void nfs40_clear_delegation_stateid(struct nfs4_state *state) | ||
2117 | { | ||
2118 | if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL) | ||
2119 | nfs_finish_clear_delegation_stateid(state); | ||
2120 | } | ||
2121 | |||
2122 | static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | ||
2123 | { | ||
2124 | /* NFSv4.0 doesn't allow for delegation recovery on open expire */ | ||
2125 | nfs40_clear_delegation_stateid(state); | ||
2126 | return nfs4_open_expired(sp, state); | ||
2127 | } | ||
2128 | |||
2112 | #if defined(CONFIG_NFS_V4_1) | 2129 | #if defined(CONFIG_NFS_V4_1) |
2113 | static void nfs41_clear_delegation_stateid(struct nfs4_state *state) | 2130 | static void nfs41_check_delegation_stateid(struct nfs4_state *state) |
2114 | { | 2131 | { |
2115 | struct nfs_server *server = NFS_SERVER(state->inode); | 2132 | struct nfs_server *server = NFS_SERVER(state->inode); |
2116 | nfs4_stateid *stateid = &state->stateid; | 2133 | nfs4_stateid stateid; |
2117 | struct nfs_delegation *delegation; | 2134 | struct nfs_delegation *delegation; |
2118 | struct rpc_cred *cred = NULL; | 2135 | struct rpc_cred *cred; |
2119 | int status = -NFS4ERR_BAD_STATEID; | 2136 | int status; |
2120 | |||
2121 | /* If a state reset has been done, test_stateid is unneeded */ | ||
2122 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | ||
2123 | return; | ||
2124 | 2137 | ||
2125 | /* Get the delegation credential for use by test/free_stateid */ | 2138 | /* Get the delegation credential for use by test/free_stateid */ |
2126 | rcu_read_lock(); | 2139 | rcu_read_lock(); |
2127 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | 2140 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); |
2128 | if (delegation != NULL && | 2141 | if (delegation == NULL) { |
2129 | nfs4_stateid_match(&delegation->stateid, stateid)) { | ||
2130 | cred = get_rpccred(delegation->cred); | ||
2131 | rcu_read_unlock(); | ||
2132 | status = nfs41_test_stateid(server, stateid, cred); | ||
2133 | trace_nfs4_test_delegation_stateid(state, NULL, status); | ||
2134 | } else | ||
2135 | rcu_read_unlock(); | 2142 | rcu_read_unlock(); |
2143 | return; | ||
2144 | } | ||
2145 | |||
2146 | nfs4_stateid_copy(&stateid, &delegation->stateid); | ||
2147 | cred = get_rpccred(delegation->cred); | ||
2148 | rcu_read_unlock(); | ||
2149 | status = nfs41_test_stateid(server, &stateid, cred); | ||
2150 | trace_nfs4_test_delegation_stateid(state, NULL, status); | ||
2136 | 2151 | ||
2137 | if (status != NFS_OK) { | 2152 | if (status != NFS_OK) { |
2138 | /* Free the stateid unless the server explicitly | 2153 | /* Free the stateid unless the server explicitly |
2139 | * informs us the stateid is unrecognized. */ | 2154 | * informs us the stateid is unrecognized. */ |
2140 | if (status != -NFS4ERR_BAD_STATEID) | 2155 | if (status != -NFS4ERR_BAD_STATEID) |
2141 | nfs41_free_stateid(server, stateid, cred); | 2156 | nfs41_free_stateid(server, &stateid, cred); |
2142 | nfs_remove_bad_delegation(state->inode); | 2157 | nfs_finish_clear_delegation_stateid(state); |
2143 | |||
2144 | write_seqlock(&state->seqlock); | ||
2145 | nfs4_stateid_copy(&state->stateid, &state->open_stateid); | ||
2146 | write_sequnlock(&state->seqlock); | ||
2147 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2148 | } | 2158 | } |
2149 | 2159 | ||
2150 | if (cred != NULL) | 2160 | put_rpccred(cred); |
2151 | put_rpccred(cred); | ||
2152 | } | 2161 | } |
2153 | 2162 | ||
2154 | /** | 2163 | /** |
@@ -2192,7 +2201,7 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
2192 | { | 2201 | { |
2193 | int status; | 2202 | int status; |
2194 | 2203 | ||
2195 | nfs41_clear_delegation_stateid(state); | 2204 | nfs41_check_delegation_stateid(state); |
2196 | status = nfs41_check_open_stateid(state); | 2205 | status = nfs41_check_open_stateid(state); |
2197 | if (status != NFS_OK) | 2206 | if (status != NFS_OK) |
2198 | status = nfs4_open_expired(sp, state); | 2207 | status = nfs4_open_expired(sp, state); |
@@ -2231,19 +2240,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
2231 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); | 2240 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); |
2232 | 2241 | ||
2233 | ret = _nfs4_proc_open(opendata); | 2242 | ret = _nfs4_proc_open(opendata); |
2234 | if (ret != 0) { | 2243 | if (ret != 0) |
2235 | if (ret == -ENOENT) { | ||
2236 | dentry = opendata->dentry; | ||
2237 | if (dentry->d_inode) | ||
2238 | d_delete(dentry); | ||
2239 | else if (d_unhashed(dentry)) | ||
2240 | d_add(dentry, NULL); | ||
2241 | |||
2242 | nfs_set_verifier(dentry, | ||
2243 | nfs_save_change_attribute(opendata->dir->d_inode)); | ||
2244 | } | ||
2245 | goto out; | 2244 | goto out; |
2246 | } | ||
2247 | 2245 | ||
2248 | state = nfs4_opendata_to_nfs4_state(opendata); | 2246 | state = nfs4_opendata_to_nfs4_state(opendata); |
2249 | ret = PTR_ERR(state); | 2247 | ret = PTR_ERR(state); |
@@ -4841,9 +4839,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
4841 | case -NFS4ERR_DELEG_REVOKED: | 4839 | case -NFS4ERR_DELEG_REVOKED: |
4842 | case -NFS4ERR_ADMIN_REVOKED: | 4840 | case -NFS4ERR_ADMIN_REVOKED: |
4843 | case -NFS4ERR_BAD_STATEID: | 4841 | case -NFS4ERR_BAD_STATEID: |
4844 | if (state == NULL) | ||
4845 | break; | ||
4846 | nfs_remove_bad_delegation(state->inode); | ||
4847 | case -NFS4ERR_OPENMODE: | 4842 | case -NFS4ERR_OPENMODE: |
4848 | if (state == NULL) | 4843 | if (state == NULL) |
4849 | break; | 4844 | break; |
@@ -8341,7 +8336,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | |||
8341 | static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | 8336 | static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { |
8342 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 8337 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
8343 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 8338 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
8344 | .recover_open = nfs4_open_expired, | 8339 | .recover_open = nfs40_open_expired, |
8345 | .recover_lock = nfs4_lock_expired, | 8340 | .recover_lock = nfs4_lock_expired, |
8346 | .establish_clid = nfs4_init_clientid, | 8341 | .establish_clid = nfs4_init_clientid, |
8347 | }; | 8342 | }; |
@@ -8408,8 +8403,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
8408 | | NFS_CAP_CHANGE_ATTR | 8403 | | NFS_CAP_CHANGE_ATTR |
8409 | | NFS_CAP_POSIX_LOCK | 8404 | | NFS_CAP_POSIX_LOCK |
8410 | | NFS_CAP_STATEID_NFSV41 | 8405 | | NFS_CAP_STATEID_NFSV41 |
8411 | | NFS_CAP_ATOMIC_OPEN_V1 | 8406 | | NFS_CAP_ATOMIC_OPEN_V1, |
8412 | | NFS_CAP_SEEK, | ||
8413 | .init_client = nfs41_init_client, | 8407 | .init_client = nfs41_init_client, |
8414 | .shutdown_client = nfs41_shutdown_client, | 8408 | .shutdown_client = nfs41_shutdown_client, |
8415 | .match_stateid = nfs41_match_stateid, | 8409 | .match_stateid = nfs41_match_stateid, |
@@ -8431,7 +8425,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | |||
8431 | | NFS_CAP_CHANGE_ATTR | 8425 | | NFS_CAP_CHANGE_ATTR |
8432 | | NFS_CAP_POSIX_LOCK | 8426 | | NFS_CAP_POSIX_LOCK |
8433 | | NFS_CAP_STATEID_NFSV41 | 8427 | | NFS_CAP_STATEID_NFSV41 |
8434 | | NFS_CAP_ATOMIC_OPEN_V1, | 8428 | | NFS_CAP_ATOMIC_OPEN_V1 |
8429 | | NFS_CAP_SEEK, | ||
8435 | .init_client = nfs41_init_client, | 8430 | .init_client = nfs41_init_client, |
8436 | .shutdown_client = nfs41_shutdown_client, | 8431 | .shutdown_client = nfs41_shutdown_client, |
8437 | .match_stateid = nfs41_match_stateid, | 8432 | .match_stateid = nfs41_match_stateid, |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 12493846a2d3..f83b02dc9166 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -715,8 +715,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
715 | 715 | ||
716 | if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) | 716 | if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) |
717 | nfs_release_request(req); | 717 | nfs_release_request(req); |
718 | else | ||
719 | WARN_ON_ONCE(1); | ||
720 | } | 718 | } |
721 | 719 | ||
722 | static void | 720 | static void |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 983876f24aed..47ebb4fafd87 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -1224,11 +1224,22 @@ struct nfs41_free_stateid_res { | |||
1224 | unsigned int status; | 1224 | unsigned int status; |
1225 | }; | 1225 | }; |
1226 | 1226 | ||
1227 | static inline void | ||
1228 | nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo) | ||
1229 | { | ||
1230 | kfree(cinfo->buckets); | ||
1231 | } | ||
1232 | |||
1227 | #else | 1233 | #else |
1228 | 1234 | ||
1229 | struct pnfs_ds_commit_info { | 1235 | struct pnfs_ds_commit_info { |
1230 | }; | 1236 | }; |
1231 | 1237 | ||
1238 | static inline void | ||
1239 | nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo) | ||
1240 | { | ||
1241 | } | ||
1242 | |||
1232 | #endif /* CONFIG_NFS_V4_1 */ | 1243 | #endif /* CONFIG_NFS_V4_1 */ |
1233 | 1244 | ||
1234 | #ifdef CONFIG_NFS_V4_2 | 1245 | #ifdef CONFIG_NFS_V4_2 |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index afb292cd797d..53ed8d3f8897 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1353,6 +1353,7 @@ gss_stringify_acceptor(struct rpc_cred *cred) | |||
1353 | char *string = NULL; | 1353 | char *string = NULL; |
1354 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 1354 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
1355 | struct gss_cl_ctx *ctx; | 1355 | struct gss_cl_ctx *ctx; |
1356 | unsigned int len; | ||
1356 | struct xdr_netobj *acceptor; | 1357 | struct xdr_netobj *acceptor; |
1357 | 1358 | ||
1358 | rcu_read_lock(); | 1359 | rcu_read_lock(); |
@@ -1360,15 +1361,39 @@ gss_stringify_acceptor(struct rpc_cred *cred) | |||
1360 | if (!ctx) | 1361 | if (!ctx) |
1361 | goto out; | 1362 | goto out; |
1362 | 1363 | ||
1363 | acceptor = &ctx->gc_acceptor; | 1364 | len = ctx->gc_acceptor.len; |
1365 | rcu_read_unlock(); | ||
1364 | 1366 | ||
1365 | /* no point if there's no string */ | 1367 | /* no point if there's no string */ |
1366 | if (!acceptor->len) | 1368 | if (!len) |
1367 | goto out; | 1369 | return NULL; |
1368 | 1370 | realloc: | |
1369 | string = kmalloc(acceptor->len + 1, GFP_KERNEL); | 1371 | string = kmalloc(len + 1, GFP_KERNEL); |
1370 | if (!string) | 1372 | if (!string) |
1373 | return NULL; | ||
1374 | |||
1375 | rcu_read_lock(); | ||
1376 | ctx = rcu_dereference(gss_cred->gc_ctx); | ||
1377 | |||
1378 | /* did the ctx disappear or was it replaced by one with no acceptor? */ | ||
1379 | if (!ctx || !ctx->gc_acceptor.len) { | ||
1380 | kfree(string); | ||
1381 | string = NULL; | ||
1371 | goto out; | 1382 | goto out; |
1383 | } | ||
1384 | |||
1385 | acceptor = &ctx->gc_acceptor; | ||
1386 | |||
1387 | /* | ||
1388 | * Did we find a new acceptor that's longer than the original? Allocate | ||
1389 | * a longer buffer and try again. | ||
1390 | */ | ||
1391 | if (len < acceptor->len) { | ||
1392 | len = acceptor->len; | ||
1393 | rcu_read_unlock(); | ||
1394 | kfree(string); | ||
1395 | goto realloc; | ||
1396 | } | ||
1372 | 1397 | ||
1373 | memcpy(string, acceptor->data, acceptor->len); | 1398 | memcpy(string, acceptor->data, acceptor->len); |
1374 | string[acceptor->len] = '\0'; | 1399 | string[acceptor->len] = '\0'; |