diff options
| -rw-r--r-- | include/linux/sunrpc/cache.h | 11 | ||||
| -rw-r--r-- | include/linux/sunrpc/svcauth.h | 1 | ||||
| -rw-r--r-- | include/linux/sunrpc/svcsock.h | 3 | ||||
| -rw-r--r-- | net/sunrpc/svcauth_unix.c | 47 | ||||
| -rw-r--r-- | net/sunrpc/svcsock.c | 2 |
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 | ||
| 166 | static 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 | |||
| 166 | extern int cache_check(struct cache_detail *detail, | 177 | extern 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); |
| 168 | extern void cache_flush(void); | 179 | extern 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); | |||
| 126 | extern struct auth_domain *auth_unix_lookup(struct in_addr addr); | 126 | extern struct auth_domain *auth_unix_lookup(struct in_addr addr); |
| 127 | extern int auth_unix_forget_old(struct auth_domain *dom); | 127 | extern int auth_unix_forget_old(struct auth_domain *dom); |
| 128 | extern void svcauth_unix_purge(void); | 128 | extern void svcauth_unix_purge(void); |
| 129 | extern void svcauth_unix_info_release(void *); | ||
| 129 | 130 | ||
| 130 | static inline unsigned long hash_str(char *name, int bits) | 131 | static 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 | ||
| 379 | static inline struct ip_map * | ||
| 380 | ip_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 | |||
| 399 | static inline void | ||
| 400 | ip_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 | |||
| 410 | void | ||
| 411 | svcauth_unix_info_release(void *info) | ||
| 412 | { | ||
| 413 | struct ip_map *ipm = info; | ||
| 414 | cache_put(&ipm->h, &ip_map_cache); | ||
| 415 | } | ||
| 416 | |||
| 378 | static int | 417 | static int |
| 379 | svcauth_unix_set_client(struct svc_rqst *rqstp) | 418 | svcauth_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); |
