lkml.org 
[lkml]   [2018]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.17 127/324] rds: clean up loopback rds_connections on netns deletion
    Date
    4.17-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Sowmini Varadhan <sowmini.varadhan@oracle.com>

    [ Upstream commit c809195f5523dd4d09403bbb1c9732d548aa0d1e ]

    The RDS core module creates rds_connections based on callbacks
    from rds_loop_transport when sending/receiving packets to local
    addresses.

    These connections will need to be cleaned up when they are
    created from a netns that is not init_net, and that netns is deleted.

    Add the changes aligned with the changes from
    commit ebeeb1ad9b8a ("rds: tcp: use rds_destroy_pending() to synchronize
    netns/module teardown and rds connection/workq management") for
    rds_loop_transport

    Reported-and-tested-by: syzbot+4c20b3866171ce8441d2@syzkaller.appspotmail.com
    Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com>
    Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    net/rds/connection.c | 11 +++++++++-
    net/rds/loop.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
    net/rds/loop.h | 2 +
    3 files changed, 68 insertions(+), 1 deletion(-)

    --- a/net/rds/connection.c
    +++ b/net/rds/connection.c
    @@ -659,11 +659,19 @@ static void rds_conn_info(struct socket

    int rds_conn_init(void)
    {
    + int ret;
    +
    + ret = rds_loop_net_init(); /* register pernet callback */
    + if (ret)
    + return ret;
    +
    rds_conn_slab = kmem_cache_create("rds_connection",
    sizeof(struct rds_connection),
    0, 0, NULL);
    - if (!rds_conn_slab)
    + if (!rds_conn_slab) {
    + rds_loop_net_exit();
    return -ENOMEM;
    + }

    rds_info_register_func(RDS_INFO_CONNECTIONS, rds_conn_info);
    rds_info_register_func(RDS_INFO_SEND_MESSAGES,
    @@ -676,6 +684,7 @@ int rds_conn_init(void)

    void rds_conn_exit(void)
    {
    + rds_loop_net_exit(); /* unregister pernet callback */
    rds_loop_exit();

    WARN_ON(!hlist_empty(rds_conn_hash));
    --- a/net/rds/loop.c
    +++ b/net/rds/loop.c
    @@ -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,
    };
    --- a/net/rds/loop.h
    +++ b/net/rds/loop.h
    @@ -5,6 +5,8 @@
    /* loop.c */
    extern struct rds_transport rds_loop_transport;

    +int rds_loop_net_init(void);
    +void rds_loop_net_exit(void);
    void rds_loop_exit(void);

    #endif

    \
     
     \ /
      Last update: 2018-08-23 10:56    [W:2.270 / U:0.468 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site