diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-19 15:13:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-19 15:13:02 -0500 |
commit | e95003c3f9ccbfa7ab9d265e6eb703ee2fa4cfe7 (patch) | |
tree | d70ef553a493478b91d96147d2c5e7e576ef8cee | |
parent | 981adacd394f15664364d7a9e138efe06c4c07d1 (diff) | |
parent | 146d70caaa1b87f64597743429d7da4b8073d0c9 (diff) |
Merge tag 'nfs-for-3.14-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights include stable fixes for the following bugs:
- General performance regression due to NFS_INO_INVALID_LABEL being
set when the server doesn't support labeled NFS
- Hang in the RPC code due to a socket out-of-buffer race
- Infinite loop when trying to establish the NFSv4 lease
- Use-after-free bug in the RPCSEC gss code.
- nfs4_select_rw_stateid is returning with a non-zero error value on
success
Other bug fixes:
- Potential memory scribble in the RPC bi-directional RPC code
- Pipe version reference leak
- Use the correct net namespace in the new NFSv4 migration code"
* tag 'nfs-for-3.14-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS fix error return in nfs4_select_rw_stateid
NFSv4: Use the correct net namespace in nfs4_update_server
SUNRPC: Fix a pipe_version reference leak
SUNRPC: Ensure that gss_auth isn't freed before its upcall messages
SUNRPC: Fix potential memory scribble in xprt_free_bc_request()
SUNRPC: Fix races in xs_nospace()
SUNRPC: Don't create a gss auth cache unless rpc.gssd is running
NFS: Do not set NFS_INO_INVALID_LABEL unless server supports labeled NFS
-rw-r--r-- | fs/nfs/inode.c | 14 | ||||
-rw-r--r-- | fs/nfs/internal.h | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 7 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 5 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 19 | ||||
-rw-r--r-- | net/sunrpc/backchannel_rqst.c | 6 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 6 |
8 files changed, 60 insertions, 21 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 28a0a3cbd3b7..360114ae8b82 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -164,17 +164,16 @@ static void nfs_zap_caches_locked(struct inode *inode) | |||
164 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { | 164 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { |
165 | nfs_fscache_invalidate(inode); | 165 | nfs_fscache_invalidate(inode); |
166 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | 166 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR |
167 | | NFS_INO_INVALID_LABEL | ||
168 | | NFS_INO_INVALID_DATA | 167 | | NFS_INO_INVALID_DATA |
169 | | NFS_INO_INVALID_ACCESS | 168 | | NFS_INO_INVALID_ACCESS |
170 | | NFS_INO_INVALID_ACL | 169 | | NFS_INO_INVALID_ACL |
171 | | NFS_INO_REVAL_PAGECACHE; | 170 | | NFS_INO_REVAL_PAGECACHE; |
172 | } else | 171 | } else |
173 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | 172 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR |
174 | | NFS_INO_INVALID_LABEL | ||
175 | | NFS_INO_INVALID_ACCESS | 173 | | NFS_INO_INVALID_ACCESS |
176 | | NFS_INO_INVALID_ACL | 174 | | NFS_INO_INVALID_ACL |
177 | | NFS_INO_REVAL_PAGECACHE; | 175 | | NFS_INO_REVAL_PAGECACHE; |
176 | nfs_zap_label_cache_locked(nfsi); | ||
178 | } | 177 | } |
179 | 178 | ||
180 | void nfs_zap_caches(struct inode *inode) | 179 | void nfs_zap_caches(struct inode *inode) |
@@ -266,6 +265,13 @@ nfs_init_locked(struct inode *inode, void *opaque) | |||
266 | } | 265 | } |
267 | 266 | ||
268 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | 267 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL |
268 | static void nfs_clear_label_invalid(struct inode *inode) | ||
269 | { | ||
270 | spin_lock(&inode->i_lock); | ||
271 | NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL; | ||
272 | spin_unlock(&inode->i_lock); | ||
273 | } | ||
274 | |||
269 | void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, | 275 | void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, |
270 | struct nfs4_label *label) | 276 | struct nfs4_label *label) |
271 | { | 277 | { |
@@ -283,6 +289,7 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, | |||
283 | __func__, | 289 | __func__, |
284 | (char *)label->label, | 290 | (char *)label->label, |
285 | label->len, error); | 291 | label->len, error); |
292 | nfs_clear_label_invalid(inode); | ||
286 | } | 293 | } |
287 | } | 294 | } |
288 | 295 | ||
@@ -1648,7 +1655,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1648 | inode->i_blocks = fattr->du.nfs2.blocks; | 1655 | inode->i_blocks = fattr->du.nfs2.blocks; |
1649 | 1656 | ||
1650 | /* Update attrtimeo value if we're out of the unstable period */ | 1657 | /* Update attrtimeo value if we're out of the unstable period */ |
1651 | if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) { | 1658 | if (invalid & NFS_INO_INVALID_ATTR) { |
1652 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | 1659 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); |
1653 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 1660 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
1654 | nfsi->attrtimeo_timestamp = now; | 1661 | nfsi->attrtimeo_timestamp = now; |
@@ -1661,7 +1668,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1661 | } | 1668 | } |
1662 | } | 1669 | } |
1663 | invalid &= ~NFS_INO_INVALID_ATTR; | 1670 | invalid &= ~NFS_INO_INVALID_ATTR; |
1664 | invalid &= ~NFS_INO_INVALID_LABEL; | ||
1665 | /* Don't invalidate the data if we were to blame */ | 1671 | /* Don't invalidate the data if we were to blame */ |
1666 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) | 1672 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) |
1667 | || S_ISLNK(inode->i_mode))) | 1673 | || S_ISLNK(inode->i_mode))) |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 8b5cc04a8611..b46cf5a67329 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -176,7 +176,8 @@ extern struct nfs_server *nfs4_create_server( | |||
176 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, | 176 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, |
177 | struct nfs_fh *); | 177 | struct nfs_fh *); |
178 | extern int nfs4_update_server(struct nfs_server *server, const char *hostname, | 178 | extern int nfs4_update_server(struct nfs_server *server, const char *hostname, |
179 | struct sockaddr *sap, size_t salen); | 179 | struct sockaddr *sap, size_t salen, |
180 | struct net *net); | ||
180 | extern void nfs_free_server(struct nfs_server *server); | 181 | extern void nfs_free_server(struct nfs_server *server); |
181 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 182 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
182 | struct nfs_fh *, | 183 | struct nfs_fh *, |
@@ -279,9 +280,18 @@ static inline void nfs4_label_free(struct nfs4_label *label) | |||
279 | } | 280 | } |
280 | return; | 281 | return; |
281 | } | 282 | } |
283 | |||
284 | static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) | ||
285 | { | ||
286 | if (nfs_server_capable(&nfsi->vfs_inode, NFS_CAP_SECURITY_LABEL)) | ||
287 | nfsi->cache_validity |= NFS_INO_INVALID_LABEL; | ||
288 | } | ||
282 | #else | 289 | #else |
283 | static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; } | 290 | static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; } |
284 | static inline void nfs4_label_free(void *label) {} | 291 | static inline void nfs4_label_free(void *label) {} |
292 | static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) | ||
293 | { | ||
294 | } | ||
285 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ | 295 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ |
286 | 296 | ||
287 | /* proc.c */ | 297 | /* proc.c */ |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 860ad26a5590..0e46d3d1b6cc 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -1135,6 +1135,7 @@ static int nfs_probe_destination(struct nfs_server *server) | |||
1135 | * @hostname: new end-point's hostname | 1135 | * @hostname: new end-point's hostname |
1136 | * @sap: new end-point's socket address | 1136 | * @sap: new end-point's socket address |
1137 | * @salen: size of "sap" | 1137 | * @salen: size of "sap" |
1138 | * @net: net namespace | ||
1138 | * | 1139 | * |
1139 | * The nfs_server must be quiescent before this function is invoked. | 1140 | * The nfs_server must be quiescent before this function is invoked. |
1140 | * Either its session is drained (NFSv4.1+), or its transport is | 1141 | * Either its session is drained (NFSv4.1+), or its transport is |
@@ -1143,13 +1144,13 @@ static int nfs_probe_destination(struct nfs_server *server) | |||
1143 | * Returns zero on success, or a negative errno value. | 1144 | * Returns zero on success, or a negative errno value. |
1144 | */ | 1145 | */ |
1145 | int nfs4_update_server(struct nfs_server *server, const char *hostname, | 1146 | int nfs4_update_server(struct nfs_server *server, const char *hostname, |
1146 | struct sockaddr *sap, size_t salen) | 1147 | struct sockaddr *sap, size_t salen, struct net *net) |
1147 | { | 1148 | { |
1148 | struct nfs_client *clp = server->nfs_client; | 1149 | struct nfs_client *clp = server->nfs_client; |
1149 | struct rpc_clnt *clnt = server->client; | 1150 | struct rpc_clnt *clnt = server->client; |
1150 | struct xprt_create xargs = { | 1151 | struct xprt_create xargs = { |
1151 | .ident = clp->cl_proto, | 1152 | .ident = clp->cl_proto, |
1152 | .net = &init_net, | 1153 | .net = net, |
1153 | .dstaddr = sap, | 1154 | .dstaddr = sap, |
1154 | .addrlen = salen, | 1155 | .addrlen = salen, |
1155 | .servername = hostname, | 1156 | .servername = hostname, |
@@ -1189,7 +1190,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname, | |||
1189 | error = nfs4_set_client(server, hostname, sap, salen, buf, | 1190 | error = nfs4_set_client(server, hostname, sap, salen, buf, |
1190 | clp->cl_rpcclient->cl_auth->au_flavor, | 1191 | clp->cl_rpcclient->cl_auth->au_flavor, |
1191 | clp->cl_proto, clnt->cl_timeout, | 1192 | clp->cl_proto, clnt->cl_timeout, |
1192 | clp->cl_minorversion, clp->cl_net); | 1193 | clp->cl_minorversion, net); |
1193 | nfs_put_client(clp); | 1194 | nfs_put_client(clp); |
1194 | if (error != 0) { | 1195 | if (error != 0) { |
1195 | nfs_server_insert_lists(server); | 1196 | nfs_server_insert_lists(server); |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 4e7f05d3e9db..3d5dbf80d46a 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -121,9 +121,8 @@ static int nfs4_validate_fspath(struct dentry *dentry, | |||
121 | } | 121 | } |
122 | 122 | ||
123 | static size_t nfs_parse_server_name(char *string, size_t len, | 123 | static size_t nfs_parse_server_name(char *string, size_t len, |
124 | struct sockaddr *sa, size_t salen, struct nfs_server *server) | 124 | struct sockaddr *sa, size_t salen, struct net *net) |
125 | { | 125 | { |
126 | struct net *net = rpc_net_ns(server->client); | ||
127 | ssize_t ret; | 126 | ssize_t ret; |
128 | 127 | ||
129 | ret = rpc_pton(net, string, len, sa, salen); | 128 | ret = rpc_pton(net, string, len, sa, salen); |
@@ -223,6 +222,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
223 | const struct nfs4_fs_location *location) | 222 | const struct nfs4_fs_location *location) |
224 | { | 223 | { |
225 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); | 224 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); |
225 | struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client); | ||
226 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 226 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
227 | char *mnt_path; | 227 | char *mnt_path; |
228 | unsigned int maxbuflen; | 228 | unsigned int maxbuflen; |
@@ -248,8 +248,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
248 | continue; | 248 | continue; |
249 | 249 | ||
250 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, | 250 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, |
251 | mountdata->addr, addr_bufsize, | 251 | mountdata->addr, addr_bufsize, net); |
252 | NFS_SB(mountdata->sb)); | ||
253 | if (mountdata->addrlen == 0) | 252 | if (mountdata->addrlen == 0) |
254 | continue; | 253 | continue; |
255 | 254 | ||
@@ -419,6 +418,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server, | |||
419 | const struct nfs4_fs_location *location) | 418 | const struct nfs4_fs_location *location) |
420 | { | 419 | { |
421 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); | 420 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); |
421 | struct net *net = rpc_net_ns(server->client); | ||
422 | struct sockaddr *sap; | 422 | struct sockaddr *sap; |
423 | unsigned int s; | 423 | unsigned int s; |
424 | size_t salen; | 424 | size_t salen; |
@@ -440,7 +440,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server, | |||
440 | continue; | 440 | continue; |
441 | 441 | ||
442 | salen = nfs_parse_server_name(buf->data, buf->len, | 442 | salen = nfs_parse_server_name(buf->data, buf->len, |
443 | sap, addr_bufsize, server); | 443 | sap, addr_bufsize, net); |
444 | if (salen == 0) | 444 | if (salen == 0) |
445 | continue; | 445 | continue; |
446 | rpc_set_port(sap, NFS_PORT); | 446 | rpc_set_port(sap, NFS_PORT); |
@@ -450,7 +450,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server, | |||
450 | if (hostname == NULL) | 450 | if (hostname == NULL) |
451 | break; | 451 | break; |
452 | 452 | ||
453 | error = nfs4_update_server(server, hostname, sap, salen); | 453 | error = nfs4_update_server(server, hostname, sap, salen, net); |
454 | kfree(hostname); | 454 | kfree(hostname); |
455 | if (error == 0) | 455 | if (error == 0) |
456 | break; | 456 | break; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e5be72518bd7..e1a47217c05e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1015,8 +1015,11 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, | |||
1015 | if (ret == -EIO) | 1015 | if (ret == -EIO) |
1016 | /* A lost lock - don't even consider delegations */ | 1016 | /* A lost lock - don't even consider delegations */ |
1017 | goto out; | 1017 | goto out; |
1018 | if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) | 1018 | /* returns true if delegation stateid found and copied */ |
1019 | if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) { | ||
1020 | ret = 0; | ||
1019 | goto out; | 1021 | goto out; |
1022 | } | ||
1020 | if (ret != -ENOENT) | 1023 | if (ret != -ENOENT) |
1021 | /* nfs4_copy_delegation_stateid() didn't over-write | 1024 | /* nfs4_copy_delegation_stateid() didn't over-write |
1022 | * dst, so it still has the lock stateid which we now | 1025 | * dst, so it still has the lock stateid which we now |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 6c0513a7f992..36e431ee1c90 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -108,6 +108,7 @@ struct gss_auth { | |||
108 | static DEFINE_SPINLOCK(pipe_version_lock); | 108 | static DEFINE_SPINLOCK(pipe_version_lock); |
109 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; | 109 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; |
110 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | 110 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); |
111 | static void gss_put_auth(struct gss_auth *gss_auth); | ||
111 | 112 | ||
112 | static void gss_free_ctx(struct gss_cl_ctx *); | 113 | static void gss_free_ctx(struct gss_cl_ctx *); |
113 | static const struct rpc_pipe_ops gss_upcall_ops_v0; | 114 | static const struct rpc_pipe_ops gss_upcall_ops_v0; |
@@ -320,6 +321,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) | |||
320 | if (gss_msg->ctx != NULL) | 321 | if (gss_msg->ctx != NULL) |
321 | gss_put_ctx(gss_msg->ctx); | 322 | gss_put_ctx(gss_msg->ctx); |
322 | rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue); | 323 | rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue); |
324 | gss_put_auth(gss_msg->auth); | ||
323 | kfree(gss_msg); | 325 | kfree(gss_msg); |
324 | } | 326 | } |
325 | 327 | ||
@@ -498,9 +500,12 @@ gss_alloc_msg(struct gss_auth *gss_auth, | |||
498 | default: | 500 | default: |
499 | err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); | 501 | err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); |
500 | if (err) | 502 | if (err) |
501 | goto err_free_msg; | 503 | goto err_put_pipe_version; |
502 | }; | 504 | }; |
505 | kref_get(&gss_auth->kref); | ||
503 | return gss_msg; | 506 | return gss_msg; |
507 | err_put_pipe_version: | ||
508 | put_pipe_version(gss_auth->net); | ||
504 | err_free_msg: | 509 | err_free_msg: |
505 | kfree(gss_msg); | 510 | kfree(gss_msg); |
506 | err: | 511 | err: |
@@ -991,6 +996,8 @@ gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | |||
991 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); | 996 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); |
992 | if (gss_auth->service == 0) | 997 | if (gss_auth->service == 0) |
993 | goto err_put_mech; | 998 | goto err_put_mech; |
999 | if (!gssd_running(gss_auth->net)) | ||
1000 | goto err_put_mech; | ||
994 | auth = &gss_auth->rpc_auth; | 1001 | auth = &gss_auth->rpc_auth; |
995 | auth->au_cslack = GSS_CRED_SLACK >> 2; | 1002 | auth->au_cslack = GSS_CRED_SLACK >> 2; |
996 | auth->au_rslack = GSS_VERF_SLACK >> 2; | 1003 | auth->au_rslack = GSS_VERF_SLACK >> 2; |
@@ -1062,6 +1069,12 @@ gss_free_callback(struct kref *kref) | |||
1062 | } | 1069 | } |
1063 | 1070 | ||
1064 | static void | 1071 | static void |
1072 | gss_put_auth(struct gss_auth *gss_auth) | ||
1073 | { | ||
1074 | kref_put(&gss_auth->kref, gss_free_callback); | ||
1075 | } | ||
1076 | |||
1077 | static void | ||
1065 | gss_destroy(struct rpc_auth *auth) | 1078 | gss_destroy(struct rpc_auth *auth) |
1066 | { | 1079 | { |
1067 | struct gss_auth *gss_auth = container_of(auth, | 1080 | struct gss_auth *gss_auth = container_of(auth, |
@@ -1082,7 +1095,7 @@ gss_destroy(struct rpc_auth *auth) | |||
1082 | gss_auth->gss_pipe[1] = NULL; | 1095 | gss_auth->gss_pipe[1] = NULL; |
1083 | rpcauth_destroy_credcache(auth); | 1096 | rpcauth_destroy_credcache(auth); |
1084 | 1097 | ||
1085 | kref_put(&gss_auth->kref, gss_free_callback); | 1098 | gss_put_auth(gss_auth); |
1086 | } | 1099 | } |
1087 | 1100 | ||
1088 | /* | 1101 | /* |
@@ -1253,7 +1266,7 @@ gss_destroy_nullcred(struct rpc_cred *cred) | |||
1253 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); | 1266 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); |
1254 | if (ctx) | 1267 | if (ctx) |
1255 | gss_put_ctx(ctx); | 1268 | gss_put_ctx(ctx); |
1256 | kref_put(&gss_auth->kref, gss_free_callback); | 1269 | gss_put_auth(gss_auth); |
1257 | } | 1270 | } |
1258 | 1271 | ||
1259 | static void | 1272 | static void |
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 890a29912d5a..e860d4f7ed2a 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c | |||
@@ -64,7 +64,6 @@ static void xprt_free_allocation(struct rpc_rqst *req) | |||
64 | free_page((unsigned long)xbufp->head[0].iov_base); | 64 | free_page((unsigned long)xbufp->head[0].iov_base); |
65 | xbufp = &req->rq_snd_buf; | 65 | xbufp = &req->rq_snd_buf; |
66 | free_page((unsigned long)xbufp->head[0].iov_base); | 66 | free_page((unsigned long)xbufp->head[0].iov_base); |
67 | list_del(&req->rq_bc_pa_list); | ||
68 | kfree(req); | 67 | kfree(req); |
69 | } | 68 | } |
70 | 69 | ||
@@ -168,8 +167,10 @@ out_free: | |||
168 | /* | 167 | /* |
169 | * Memory allocation failed, free the temporary list | 168 | * Memory allocation failed, free the temporary list |
170 | */ | 169 | */ |
171 | list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) | 170 | list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) { |
171 | list_del(&req->rq_bc_pa_list); | ||
172 | xprt_free_allocation(req); | 172 | xprt_free_allocation(req); |
173 | } | ||
173 | 174 | ||
174 | dprintk("RPC: setup backchannel transport failed\n"); | 175 | dprintk("RPC: setup backchannel transport failed\n"); |
175 | return -ENOMEM; | 176 | return -ENOMEM; |
@@ -198,6 +199,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) | |||
198 | xprt_dec_alloc_count(xprt, max_reqs); | 199 | xprt_dec_alloc_count(xprt, max_reqs); |
199 | list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { | 200 | list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { |
200 | dprintk("RPC: req=%p\n", req); | 201 | dprintk("RPC: req=%p\n", req); |
202 | list_del(&req->rq_bc_pa_list); | ||
201 | xprt_free_allocation(req); | 203 | xprt_free_allocation(req); |
202 | if (--max_reqs == 0) | 204 | if (--max_reqs == 0) |
203 | break; | 205 | break; |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 817a1e523969..0addefca8e77 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -510,6 +510,7 @@ static int xs_nospace(struct rpc_task *task) | |||
510 | struct rpc_rqst *req = task->tk_rqstp; | 510 | struct rpc_rqst *req = task->tk_rqstp; |
511 | struct rpc_xprt *xprt = req->rq_xprt; | 511 | struct rpc_xprt *xprt = req->rq_xprt; |
512 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 512 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
513 | struct sock *sk = transport->inet; | ||
513 | int ret = -EAGAIN; | 514 | int ret = -EAGAIN; |
514 | 515 | ||
515 | dprintk("RPC: %5u xmit incomplete (%u left of %u)\n", | 516 | dprintk("RPC: %5u xmit incomplete (%u left of %u)\n", |
@@ -527,7 +528,7 @@ static int xs_nospace(struct rpc_task *task) | |||
527 | * window size | 528 | * window size |
528 | */ | 529 | */ |
529 | set_bit(SOCK_NOSPACE, &transport->sock->flags); | 530 | set_bit(SOCK_NOSPACE, &transport->sock->flags); |
530 | transport->inet->sk_write_pending++; | 531 | sk->sk_write_pending++; |
531 | /* ...and wait for more buffer space */ | 532 | /* ...and wait for more buffer space */ |
532 | xprt_wait_for_buffer_space(task, xs_nospace_callback); | 533 | xprt_wait_for_buffer_space(task, xs_nospace_callback); |
533 | } | 534 | } |
@@ -537,6 +538,9 @@ static int xs_nospace(struct rpc_task *task) | |||
537 | } | 538 | } |
538 | 539 | ||
539 | spin_unlock_bh(&xprt->transport_lock); | 540 | spin_unlock_bh(&xprt->transport_lock); |
541 | |||
542 | /* Race breaker in case memory is freed before above code is called */ | ||
543 | sk->sk_write_space(sk); | ||
540 | return ret; | 544 | return ret; |
541 | } | 545 | } |
542 | 546 | ||