|
@@ -33,6 +33,8 @@
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/in.h>
|
|
|
+#include <net/net_namespace.h>
|
|
|
+#include <net/netns/generic.h>
|
|
|
|
|
|
#include "rds_single_path.h"
|
|
|
#include "rds.h"
|
|
@@ -40,6 +42,17 @@
|
|
|
|
|
|
static DEFINE_SPINLOCK(loop_conns_lock);
|
|
|
static LIST_HEAD(loop_conns);
|
|
|
+static atomic_t rds_loop_unloading = ATOMIC_INIT(0);
|
|
|
+
|
|
|
+static void rds_loop_set_unloading(void)
|
|
|
+{
|
|
|
+ atomic_set(&rds_loop_unloading, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static bool rds_loop_is_unloading(struct rds_connection *conn)
|
|
|
+{
|
|
|
+ return atomic_read(&rds_loop_unloading) != 0;
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
* This 'loopback' transport is a special case for flows that originate
|
|
@@ -165,6 +178,8 @@ void rds_loop_exit(void)
|
|
|
struct rds_loop_connection *lc, *_lc;
|
|
|
LIST_HEAD(tmp_list);
|
|
|
|
|
|
+ rds_loop_set_unloading();
|
|
|
+ synchronize_rcu();
|
|
|
/* avoid calling conn_destroy with irqs off */
|
|
|
spin_lock_irq(&loop_conns_lock);
|
|
|
list_splice(&loop_conns, &tmp_list);
|
|
@@ -177,6 +192,46 @@ void rds_loop_exit(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void rds_loop_kill_conns(struct net *net)
|
|
|
+{
|
|
|
+ struct rds_loop_connection *lc, *_lc;
|
|
|
+ LIST_HEAD(tmp_list);
|
|
|
+
|
|
|
+ spin_lock_irq(&loop_conns_lock);
|
|
|
+ list_for_each_entry_safe(lc, _lc, &loop_conns, loop_node) {
|
|
|
+ struct net *c_net = read_pnet(&lc->conn->c_net);
|
|
|
+
|
|
|
+ if (net != c_net)
|
|
|
+ continue;
|
|
|
+ list_move_tail(&lc->loop_node, &tmp_list);
|
|
|
+ }
|
|
|
+ spin_unlock_irq(&loop_conns_lock);
|
|
|
+
|
|
|
+ list_for_each_entry_safe(lc, _lc, &tmp_list, loop_node) {
|
|
|
+ WARN_ON(lc->conn->c_passive);
|
|
|
+ rds_conn_destroy(lc->conn);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void __net_exit rds_loop_exit_net(struct net *net)
|
|
|
+{
|
|
|
+ rds_loop_kill_conns(net);
|
|
|
+}
|
|
|
+
|
|
|
+static struct pernet_operations rds_loop_net_ops = {
|
|
|
+ .exit = rds_loop_exit_net,
|
|
|
+};
|
|
|
+
|
|
|
+int rds_loop_net_init(void)
|
|
|
+{
|
|
|
+ return register_pernet_device(&rds_loop_net_ops);
|
|
|
+}
|
|
|
+
|
|
|
+void rds_loop_net_exit(void)
|
|
|
+{
|
|
|
+ unregister_pernet_device(&rds_loop_net_ops);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This is missing .xmit_* because loop doesn't go through generic
|
|
|
* rds_send_xmit() and doesn't call rds_recv_incoming(). .listen_stop and
|
|
@@ -194,4 +249,5 @@ struct rds_transport rds_loop_transport = {
|
|
|
.inc_free = rds_loop_inc_free,
|
|
|
.t_name = "loopback",
|
|
|
.t_type = RDS_TRANS_LOOP,
|
|
|
+ .t_unloading = rds_loop_is_unloading,
|
|
|
};
|