aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2007-04-17 01:53:25 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-04-17 19:36:27 -0400
commit30f3deeee81cf22546da1b0b89a937bb991dea23 (patch)
tree3747930c11b5cf0b25c96ddd161e541c1b00010c /net/sunrpc
parent94256dd680f837dc14dd7d1377c5326fb3362721 (diff)
knfsd: use a spinlock to protect sk_info_authunix
sk_info_authunix is not being protected properly so the object that it points to can be cache_put twice, leading to corruption. We borrow svsk->sk_defer_lock to provide the protection. We should probably rename that lock to have a more generic name - later. Thanks to Gabriel for reporting this. Cc: Greg Banks <gnb@melbourne.sgi.com> Cc: Gabriel Barazer <gabriel@oxeva.fr> Signed-off-by: Neil Brown <neilb@suse.de> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/svcauth_unix.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 9bae4090254c..2bd23ea2aa8b 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -383,7 +383,10 @@ void svcauth_unix_purge(void)
383static inline struct ip_map * 383static inline struct ip_map *
384ip_map_cached_get(struct svc_rqst *rqstp) 384ip_map_cached_get(struct svc_rqst *rqstp)
385{ 385{
386 struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix; 386 struct ip_map *ipm;
387 struct svc_sock *svsk = rqstp->rq_sock;
388 spin_lock_bh(&svsk->sk_defer_lock);
389 ipm = svsk->sk_info_authunix;
387 if (ipm != NULL) { 390 if (ipm != NULL) {
388 if (!cache_valid(&ipm->h)) { 391 if (!cache_valid(&ipm->h)) {
389 /* 392 /*
@@ -391,12 +394,14 @@ ip_map_cached_get(struct svc_rqst *rqstp)
391 * remembered, e.g. by a second mount from the 394 * remembered, e.g. by a second mount from the
392 * same IP address. 395 * same IP address.
393 */ 396 */
394 rqstp->rq_sock->sk_info_authunix = NULL; 397 svsk->sk_info_authunix = NULL;
398 spin_unlock_bh(&svsk->sk_defer_lock);
395 cache_put(&ipm->h, &ip_map_cache); 399 cache_put(&ipm->h, &ip_map_cache);
396 return NULL; 400 return NULL;
397 } 401 }
398 cache_get(&ipm->h); 402 cache_get(&ipm->h);
399 } 403 }
404 spin_unlock_bh(&svsk->sk_defer_lock);
400 return ipm; 405 return ipm;
401} 406}
402 407
@@ -405,9 +410,15 @@ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
405{ 410{
406 struct svc_sock *svsk = rqstp->rq_sock; 411 struct svc_sock *svsk = rqstp->rq_sock;
407 412
408 if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL) 413 spin_lock_bh(&svsk->sk_defer_lock);
409 svsk->sk_info_authunix = ipm; /* newly cached, keep the reference */ 414 if (svsk->sk_sock->type == SOCK_STREAM &&
410 else 415 svsk->sk_info_authunix == NULL) {
416 /* newly cached, keep the reference */
417 svsk->sk_info_authunix = ipm;
418 ipm = NULL;
419 }
420 spin_unlock_bh(&svsk->sk_defer_lock);
421 if (ipm)
411 cache_put(&ipm->h, &ip_map_cache); 422 cache_put(&ipm->h, &ip_map_cache);
412} 423}
413 424