aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/cache.h11
-rw-r--r--include/linux/sunrpc/svcauth.h1
-rw-r--r--include/linux/sunrpc/svcsock.h3
-rw-r--r--net/sunrpc/svcauth_unix.c47
-rw-r--r--net/sunrpc/svcsock.c2
5 files changed, 61 insertions, 3 deletions
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index b5612c958cce..3699dff7db8f 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -163,6 +163,17 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
163 kref_put(&h->ref, cd->cache_put); 163 kref_put(&h->ref, cd->cache_put);
164} 164}
165 165
166static inline int cache_valid(struct cache_head *h)
167{
168 /* If an item has been unhashed pending removal when
169 * the refcount drops to 0, the expiry_time will be
170 * set to 0. We don't want to consider such items
171 * valid in this context even though CACHE_VALID is
172 * set.
173 */
174 return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags));
175}
176
166extern int cache_check(struct cache_detail *detail, 177extern int cache_check(struct cache_detail *detail,
167 struct cache_head *h, struct cache_req *rqstp); 178 struct cache_head *h, struct cache_req *rqstp);
168extern void cache_flush(void); 179extern void cache_flush(void);
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index a6601650deeb..de92619b0826 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -126,6 +126,7 @@ extern struct auth_domain *auth_domain_find(char *name);
126extern struct auth_domain *auth_unix_lookup(struct in_addr addr); 126extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
127extern int auth_unix_forget_old(struct auth_domain *dom); 127extern int auth_unix_forget_old(struct auth_domain *dom);
128extern void svcauth_unix_purge(void); 128extern void svcauth_unix_purge(void);
129extern void svcauth_unix_info_release(void *);
129 130
130static inline unsigned long hash_str(char *name, int bits) 131static inline unsigned long hash_str(char *name, int bits)
131{ 132{
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 4c296152cbfa..98b21ad370fd 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -54,6 +54,9 @@ struct svc_sock {
54 int sk_reclen; /* length of record */ 54 int sk_reclen; /* length of record */
55 int sk_tcplen; /* current read length */ 55 int sk_tcplen; /* current read length */
56 time_t sk_lastrecv; /* time of last received request */ 56 time_t sk_lastrecv; /* time of last received request */
57
58 /* cache of various info for TCP sockets */
59 void *sk_info_authunix;
57}; 60};
58 61
59/* 62/*
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 40d41a2831d7..e1bd933629fe 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -9,6 +9,7 @@
9#include <linux/seq_file.h> 9#include <linux/seq_file.h>
10#include <linux/hash.h> 10#include <linux/hash.h>
11#include <linux/string.h> 11#include <linux/string.h>
12#include <net/sock.h>
12 13
13#define RPCDBG_FACILITY RPCDBG_AUTH 14#define RPCDBG_FACILITY RPCDBG_AUTH
14 15
@@ -375,6 +376,44 @@ void svcauth_unix_purge(void)
375 cache_purge(&ip_map_cache); 376 cache_purge(&ip_map_cache);
376} 377}
377 378
379static inline struct ip_map *
380ip_map_cached_get(struct svc_rqst *rqstp)
381{
382 struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix;
383 if (ipm != NULL) {
384 if (!cache_valid(&ipm->h)) {
385 /*
386 * The entry has been invalidated since it was
387 * remembered, e.g. by a second mount from the
388 * same IP address.
389 */
390 rqstp->rq_sock->sk_info_authunix = NULL;
391 cache_put(&ipm->h, &ip_map_cache);
392 return NULL;
393 }
394 cache_get(&ipm->h);
395 }
396 return ipm;
397}
398
399static inline void
400ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
401{
402 struct svc_sock *svsk = rqstp->rq_sock;
403
404 if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL)
405 svsk->sk_info_authunix = ipm; /* newly cached, keep the reference */
406 else
407 cache_put(&ipm->h, &ip_map_cache);
408}
409
410void
411svcauth_unix_info_release(void *info)
412{
413 struct ip_map *ipm = info;
414 cache_put(&ipm->h, &ip_map_cache);
415}
416
378static int 417static int
379svcauth_unix_set_client(struct svc_rqst *rqstp) 418svcauth_unix_set_client(struct svc_rqst *rqstp)
380{ 419{
@@ -384,8 +423,10 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
384 if (rqstp->rq_proc == 0) 423 if (rqstp->rq_proc == 0)
385 return SVC_OK; 424 return SVC_OK;
386 425
387 ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, 426 ipm = ip_map_cached_get(rqstp);
388 rqstp->rq_addr.sin_addr); 427 if (ipm == NULL)
428 ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
429 rqstp->rq_addr.sin_addr);
389 430
390 if (ipm == NULL) 431 if (ipm == NULL)
391 return SVC_DENIED; 432 return SVC_DENIED;
@@ -400,7 +441,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
400 case 0: 441 case 0:
401 rqstp->rq_client = &ipm->m_client->h; 442 rqstp->rq_client = &ipm->m_client->h;
402 kref_get(&rqstp->rq_client->ref); 443 kref_get(&rqstp->rq_client->ref);
403 cache_put(&ipm->h, &ip_map_cache); 444 ip_map_cached_put(rqstp, ipm);
404 break; 445 break;
405 } 446 }
406 return SVC_OK; 447 return SVC_OK;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 1d512337ccd9..b39e7e2b648f 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1610,6 +1610,8 @@ svc_delete_socket(struct svc_sock *svsk)
1610 sockfd_put(svsk->sk_sock); 1610 sockfd_put(svsk->sk_sock);
1611 else 1611 else
1612 sock_release(svsk->sk_sock); 1612 sock_release(svsk->sk_sock);
1613 if (svsk->sk_info_authunix != NULL)
1614 svcauth_unix_info_release(svsk->sk_info_authunix);
1613 kfree(svsk); 1615 kfree(svsk);
1614 } else { 1616 } else {
1615 spin_unlock_bh(&serv->sv_lock); 1617 spin_unlock_bh(&serv->sv_lock);