On Tue, May 07, 2019 at 12:03:36AM -0400, Jason Wang wrote: > When a queue(tfile) is detached through __tun_detach(), we move the > last enabled tfile to the position where detached one sit but don't > NULL out last position. We expect to synchronize the datapath through > tun->numqueues. Unfortunately, this won't work since we're lacking > sufficient mechanism to order or synchronize the access to > tun->numqueues. > > To fix this, NULL out the last position during detaching and check > RCU protected tfile against NULL instead of checking tun->numqueues in > datapath. > > Cc: YueHaibing <yuehaib...@huawei.com> > Cc: Cong Wang <xiyou.wangc...@gmail.com> > Cc: weiyongjun (A) <weiyongj...@huawei.com> > Cc: Eric Dumazet <eric.duma...@gmail.com> > Fixes: c8d68e6be1c3b ("tuntap: multiqueue support") > Signed-off-by: Jason Wang <jasow...@redhat.com> > --- > Changes from V1: > - keep the check in tun_xdp_xmit() > --- > drivers/net/tun.c | 8 +++++++- > 1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c > index e9ca1c0..32a0b23 100644 > --- a/drivers/net/tun.c > +++ b/drivers/net/tun.c > @@ -700,6 +700,8 @@ static void __tun_detach(struct tun_file *tfile, bool > clean) > tun->tfiles[tun->numqueues - 1]); > ntfile = rtnl_dereference(tun->tfiles[index]); > ntfile->queue_index = index; > + rcu_assign_pointer(tun->tfiles[tun->numqueues - 1], > + NULL); > > --tun->numqueues; > if (clean) { > @@ -1082,7 +1084,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, > struct net_device *dev) > tfile = rcu_dereference(tun->tfiles[txq]); > > /* Drop packet if interface is not attached */ > - if (txq >= tun->numqueues) > + if (!tfile) > goto drop; > > if (!rcu_dereference(tun->steering_prog))
Hmm don't we need to range check txq? > @@ -1313,6 +1315,10 @@ static int tun_xdp_xmit(struct net_device *dev, int n, > > tfile = rcu_dereference(tun->tfiles[smp_processor_id() % > numqueues]); > + if (!tfile) { > + rcu_read_unlock(); > + return -ENXIO; /* Caller will free/return all frames */ > + } > > spin_lock(&tfile->tx_ring.producer_lock); > for (i = 0; i < n; i++) { > -- > 1.8.3.1