aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/svc_xprt.h1
-rw-r--r--net/sunrpc/svc_xprt.c45
2 files changed, 46 insertions, 0 deletions
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 78512cfe1fe6..b7dabc4baafd 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -128,6 +128,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
128 const unsigned short port); 128 const unsigned short port);
129int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); 129int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
130void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt); 130void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt);
131void svc_age_temp_xprts_now(struct svc_serv *, struct sockaddr *);
131 132
132static inline void svc_xprt_get(struct svc_xprt *xprt) 133static inline void svc_xprt_get(struct svc_xprt *xprt)
133{ 134{
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index a6cbb2104667..7422f28818b2 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -10,11 +10,13 @@
10#include <linux/kthread.h> 10#include <linux/kthread.h>
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <net/sock.h> 12#include <net/sock.h>
13#include <linux/sunrpc/addr.h>
13#include <linux/sunrpc/stats.h> 14#include <linux/sunrpc/stats.h>
14#include <linux/sunrpc/svc_xprt.h> 15#include <linux/sunrpc/svc_xprt.h>
15#include <linux/sunrpc/svcsock.h> 16#include <linux/sunrpc/svcsock.h>
16#include <linux/sunrpc/xprt.h> 17#include <linux/sunrpc/xprt.h>
17#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/netdevice.h>
18#include <trace/events/sunrpc.h> 20#include <trace/events/sunrpc.h>
19 21
20#define RPCDBG_FACILITY RPCDBG_SVCXPRT 22#define RPCDBG_FACILITY RPCDBG_SVCXPRT
@@ -938,6 +940,49 @@ static void svc_age_temp_xprts(unsigned long closure)
938 mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); 940 mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
939} 941}
940 942
943/* Close temporary transports whose xpt_local matches server_addr immediately
944 * instead of waiting for them to be picked up by the timer.
945 *
946 * This is meant to be called from a notifier_block that runs when an ip
947 * address is deleted.
948 */
949void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
950{
951 struct svc_xprt *xprt;
952 struct svc_sock *svsk;
953 struct socket *sock;
954 struct list_head *le, *next;
955 LIST_HEAD(to_be_closed);
956 struct linger no_linger = {
957 .l_onoff = 1,
958 .l_linger = 0,
959 };
960
961 spin_lock_bh(&serv->sv_lock);
962 list_for_each_safe(le, next, &serv->sv_tempsocks) {
963 xprt = list_entry(le, struct svc_xprt, xpt_list);
964 if (rpc_cmp_addr(server_addr, (struct sockaddr *)
965 &xprt->xpt_local)) {
966 dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
967 list_move(le, &to_be_closed);
968 }
969 }
970 spin_unlock_bh(&serv->sv_lock);
971
972 while (!list_empty(&to_be_closed)) {
973 le = to_be_closed.next;
974 list_del_init(le);
975 xprt = list_entry(le, struct svc_xprt, xpt_list);
976 dprintk("svc_age_temp_xprts_now: closing %p\n", xprt);
977 svsk = container_of(xprt, struct svc_sock, sk_xprt);
978 sock = svsk->sk_sock;
979 kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
980 (char *)&no_linger, sizeof(no_linger));
981 svc_close_xprt(xprt);
982 }
983}
984EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
985
941static void call_xpt_users(struct svc_xprt *xprt) 986static void call_xpt_users(struct svc_xprt *xprt)
942{ 987{
943 struct svc_xpt_user *u; 988 struct svc_xpt_user *u;