14 Dec, 2017

1 commit

  • [ Upstream commit 89ad2fa3f043a1e8daae193bcb5fe34d5f8caf28 ]

    pcpu_freelist_pop() needs the same lockdep awareness than
    pcpu_freelist_populate() to avoid a false positive.

    [ INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected ]

    switchto-defaul/12508 [HC0[0]:SC0[6]:HE0:SE0] is trying to acquire:
    (&htab->buckets[i].lock){......}, at: [] __htab_percpu_map_update_elem+0x1cb/0x300

    and this task is already holding:
    (dev_queue->dev->qdisc_class ?: &qdisc_tx_lock#2){+.-...}, at: [] __dev_queue_xmit+0
    x868/0x1240
    which would create a new lock dependency:
    (dev_queue->dev->qdisc_class ?: &qdisc_tx_lock#2){+.-...} -> (&htab->buckets[i].lock){......}

    but this new dependency connects a SOFTIRQ-irq-safe lock:
    (dev_queue->dev->qdisc_class ?: &qdisc_tx_lock#2){+.-...}
    ... which became SOFTIRQ-irq-safe at:
    [] __lock_acquire+0x42b/0x1f10
    [] lock_acquire+0xbc/0x1b0
    [] _raw_spin_lock+0x38/0x50
    [] __dev_queue_xmit+0x868/0x1240
    [] dev_queue_xmit+0x10/0x20
    [] ip_finish_output2+0x439/0x590
    [] ip_finish_output+0x150/0x2f0
    [] ip_output+0x7d/0x260
    [] ip_local_out+0x5e/0xe0
    [] ip_queue_xmit+0x205/0x620
    [] tcp_transmit_skb+0x5a8/0xcb0
    [] tcp_write_xmit+0x242/0x1070
    [] __tcp_push_pending_frames+0x3c/0xf0
    [] tcp_rcv_established+0x312/0x700
    [] tcp_v4_do_rcv+0x11c/0x200
    [] tcp_v4_rcv+0xaa2/0xc30
    [] ip_local_deliver_finish+0xa7/0x240
    [] ip_local_deliver+0x66/0x200
    [] ip_rcv_finish+0xdd/0x560
    [] ip_rcv+0x295/0x510
    [] __netif_receive_skb_core+0x988/0x1020
    [] __netif_receive_skb+0x21/0x70
    [] process_backlog+0x6f/0x230
    [] net_rx_action+0x229/0x420
    [] __do_softirq+0xd8/0x43d
    [] do_softirq_own_stack+0x1c/0x30
    [] do_softirq+0x55/0x60
    [] __local_bh_enable_ip+0xa8/0xb0
    [] cpu_startup_entry+0x1c7/0x500
    [] start_secondary+0x113/0x140

    to a SOFTIRQ-irq-unsafe lock:
    (&head->lock){+.+...}
    ... which became SOFTIRQ-irq-unsafe at:
    ... [] __lock_acquire+0x82f/0x1f10
    [] lock_acquire+0xbc/0x1b0
    [] _raw_spin_lock+0x38/0x50
    [] pcpu_freelist_pop+0x7a/0xb0
    [] htab_map_alloc+0x50c/0x5f0
    [] SyS_bpf+0x265/0x1200
    [] entry_SYSCALL_64_fastpath+0x12/0x17

    other info that might help us debug this:

    Chain exists of:
    dev_queue->dev->qdisc_class ?: &qdisc_tx_lock#2 --> &htab->buckets[i].lock --> &head->lock

    Possible interrupt unsafe locking scenario:

    CPU0 CPU1
    ---- ----
    lock(&head->lock);
    local_irq_disable();
    lock(dev_queue->dev->qdisc_class ?: &qdisc_tx_lock#2);
    lock(&htab->buckets[i].lock);

    lock(dev_queue->dev->qdisc_class ?: &qdisc_tx_lock#2);

    *** DEADLOCK ***

    Fixes: e19494edab82 ("bpf: introduce percpu_freelist")
    Signed-off-by: Eric Dumazet
    Signed-off-by: David S. Miller
    Signed-off-by: Sasha Levin
    Signed-off-by: Greg Kroah-Hartman

    Eric Dumazet
     

09 Mar, 2016

1 commit

  • Introduce simple percpu_freelist to keep single list of elements
    spread across per-cpu singly linked lists.

    /* push element into the list */
    void pcpu_freelist_push(struct pcpu_freelist *, struct pcpu_freelist_node *);

    /* pop element from the list */
    struct pcpu_freelist_node *pcpu_freelist_pop(struct pcpu_freelist *);

    The object is pushed to the current cpu list.
    Pop first trying to get the object from the current cpu list,
    if it's empty goes to the neigbour cpu list.

    For bpf program usage pattern the collision rate is very low,
    since programs push and pop the objects typically on the same cpu.

    Signed-off-by: Alexei Starovoitov
    Signed-off-by: David S. Miller

    Alexei Starovoitov