diff options
author | David S. Miller <davem@davemloft.net> | 2008-07-31 19:58:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-31 19:58:50 -0400 |
commit | c3f26a269c2421f97f10cf8ed05d5099b573af4d (patch) | |
tree | d0602cbb48742b3e39ab6bdcaa08c342d4cd2cae /include/linux | |
parent | 967ab999a090b1a4e7d3c7febfd6d89b42fb4cf4 (diff) |
netdev: Fix lockdep warnings in multiqueue configurations.
When support for multiple TX queues were added, the
netif_tx_lock() routines we converted to iterate over
all TX queues and grab each queue's spinlock.
This causes heartburn for lockdep and it's not a healthy
thing to do with lots of TX queues anyways.
So modify this to use a top-level lock and a "frozen"
state for the individual TX queues.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/netdevice.h | 86 |
1 files changed, 55 insertions, 31 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b4d056ceab96..ee583f642a9f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -440,6 +440,7 @@ static inline void napi_synchronize(const struct napi_struct *n) | |||
440 | enum netdev_queue_state_t | 440 | enum netdev_queue_state_t |
441 | { | 441 | { |
442 | __QUEUE_STATE_XOFF, | 442 | __QUEUE_STATE_XOFF, |
443 | __QUEUE_STATE_FROZEN, | ||
443 | }; | 444 | }; |
444 | 445 | ||
445 | struct netdev_queue { | 446 | struct netdev_queue { |
@@ -636,7 +637,7 @@ struct net_device | |||
636 | unsigned int real_num_tx_queues; | 637 | unsigned int real_num_tx_queues; |
637 | 638 | ||
638 | unsigned long tx_queue_len; /* Max frames per queue allowed */ | 639 | unsigned long tx_queue_len; /* Max frames per queue allowed */ |
639 | 640 | spinlock_t tx_global_lock; | |
640 | /* | 641 | /* |
641 | * One part is mostly used on xmit path (device) | 642 | * One part is mostly used on xmit path (device) |
642 | */ | 643 | */ |
@@ -1099,6 +1100,11 @@ static inline int netif_queue_stopped(const struct net_device *dev) | |||
1099 | return netif_tx_queue_stopped(netdev_get_tx_queue(dev, 0)); | 1100 | return netif_tx_queue_stopped(netdev_get_tx_queue(dev, 0)); |
1100 | } | 1101 | } |
1101 | 1102 | ||
1103 | static inline int netif_tx_queue_frozen(const struct netdev_queue *dev_queue) | ||
1104 | { | ||
1105 | return test_bit(__QUEUE_STATE_FROZEN, &dev_queue->state); | ||
1106 | } | ||
1107 | |||
1102 | /** | 1108 | /** |
1103 | * netif_running - test if up | 1109 | * netif_running - test if up |
1104 | * @dev: network device | 1110 | * @dev: network device |
@@ -1475,6 +1481,26 @@ static inline void __netif_tx_lock_bh(struct netdev_queue *txq) | |||
1475 | txq->xmit_lock_owner = smp_processor_id(); | 1481 | txq->xmit_lock_owner = smp_processor_id(); |
1476 | } | 1482 | } |
1477 | 1483 | ||
1484 | static inline int __netif_tx_trylock(struct netdev_queue *txq) | ||
1485 | { | ||
1486 | int ok = spin_trylock(&txq->_xmit_lock); | ||
1487 | if (likely(ok)) | ||
1488 | txq->xmit_lock_owner = smp_processor_id(); | ||
1489 | return ok; | ||
1490 | } | ||
1491 | |||
1492 | static inline void __netif_tx_unlock(struct netdev_queue *txq) | ||
1493 | { | ||
1494 | txq->xmit_lock_owner = -1; | ||
1495 | spin_unlock(&txq->_xmit_lock); | ||
1496 | } | ||
1497 | |||
1498 | static inline void __netif_tx_unlock_bh(struct netdev_queue *txq) | ||
1499 | { | ||
1500 | txq->xmit_lock_owner = -1; | ||
1501 | spin_unlock_bh(&txq->_xmit_lock); | ||
1502 | } | ||
1503 | |||
1478 | /** | 1504 | /** |
1479 | * netif_tx_lock - grab network device transmit lock | 1505 | * netif_tx_lock - grab network device transmit lock |
1480 | * @dev: network device | 1506 | * @dev: network device |
@@ -1484,12 +1510,23 @@ static inline void __netif_tx_lock_bh(struct netdev_queue *txq) | |||
1484 | */ | 1510 | */ |
1485 | static inline void netif_tx_lock(struct net_device *dev) | 1511 | static inline void netif_tx_lock(struct net_device *dev) |
1486 | { | 1512 | { |
1487 | int cpu = smp_processor_id(); | ||
1488 | unsigned int i; | 1513 | unsigned int i; |
1514 | int cpu; | ||
1489 | 1515 | ||
1516 | spin_lock(&dev->tx_global_lock); | ||
1517 | cpu = smp_processor_id(); | ||
1490 | for (i = 0; i < dev->num_tx_queues; i++) { | 1518 | for (i = 0; i < dev->num_tx_queues; i++) { |
1491 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 1519 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); |
1520 | |||
1521 | /* We are the only thread of execution doing a | ||
1522 | * freeze, but we have to grab the _xmit_lock in | ||
1523 | * order to synchronize with threads which are in | ||
1524 | * the ->hard_start_xmit() handler and already | ||
1525 | * checked the frozen bit. | ||
1526 | */ | ||
1492 | __netif_tx_lock(txq, cpu); | 1527 | __netif_tx_lock(txq, cpu); |
1528 | set_bit(__QUEUE_STATE_FROZEN, &txq->state); | ||
1529 | __netif_tx_unlock(txq); | ||
1493 | } | 1530 | } |
1494 | } | 1531 | } |
1495 | 1532 | ||
@@ -1499,40 +1536,22 @@ static inline void netif_tx_lock_bh(struct net_device *dev) | |||
1499 | netif_tx_lock(dev); | 1536 | netif_tx_lock(dev); |
1500 | } | 1537 | } |
1501 | 1538 | ||
1502 | static inline int __netif_tx_trylock(struct netdev_queue *txq) | ||
1503 | { | ||
1504 | int ok = spin_trylock(&txq->_xmit_lock); | ||
1505 | if (likely(ok)) | ||
1506 | txq->xmit_lock_owner = smp_processor_id(); | ||
1507 | return ok; | ||
1508 | } | ||
1509 | |||
1510 | static inline int netif_tx_trylock(struct net_device *dev) | ||
1511 | { | ||
1512 | return __netif_tx_trylock(netdev_get_tx_queue(dev, 0)); | ||
1513 | } | ||
1514 | |||
1515 | static inline void __netif_tx_unlock(struct netdev_queue *txq) | ||
1516 | { | ||
1517 | txq->xmit_lock_owner = -1; | ||
1518 | spin_unlock(&txq->_xmit_lock); | ||
1519 | } | ||
1520 | |||
1521 | static inline void __netif_tx_unlock_bh(struct netdev_queue *txq) | ||
1522 | { | ||
1523 | txq->xmit_lock_owner = -1; | ||
1524 | spin_unlock_bh(&txq->_xmit_lock); | ||
1525 | } | ||
1526 | |||
1527 | static inline void netif_tx_unlock(struct net_device *dev) | 1539 | static inline void netif_tx_unlock(struct net_device *dev) |
1528 | { | 1540 | { |
1529 | unsigned int i; | 1541 | unsigned int i; |
1530 | 1542 | ||
1531 | for (i = 0; i < dev->num_tx_queues; i++) { | 1543 | for (i = 0; i < dev->num_tx_queues; i++) { |
1532 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 1544 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); |
1533 | __netif_tx_unlock(txq); | ||
1534 | } | ||
1535 | 1545 | ||
1546 | /* No need to grab the _xmit_lock here. If the | ||
1547 | * queue is not stopped for another reason, we | ||
1548 | * force a schedule. | ||
1549 | */ | ||
1550 | clear_bit(__QUEUE_STATE_FROZEN, &txq->state); | ||
1551 | if (!test_bit(__QUEUE_STATE_XOFF, &txq->state)) | ||
1552 | __netif_schedule(txq->qdisc); | ||
1553 | } | ||
1554 | spin_unlock(&dev->tx_global_lock); | ||
1536 | } | 1555 | } |
1537 | 1556 | ||
1538 | static inline void netif_tx_unlock_bh(struct net_device *dev) | 1557 | static inline void netif_tx_unlock_bh(struct net_device *dev) |
@@ -1556,13 +1575,18 @@ static inline void netif_tx_unlock_bh(struct net_device *dev) | |||
1556 | static inline void netif_tx_disable(struct net_device *dev) | 1575 | static inline void netif_tx_disable(struct net_device *dev) |
1557 | { | 1576 | { |
1558 | unsigned int i; | 1577 | unsigned int i; |
1578 | int cpu; | ||
1559 | 1579 | ||
1560 | netif_tx_lock_bh(dev); | 1580 | local_bh_disable(); |
1581 | cpu = smp_processor_id(); | ||
1561 | for (i = 0; i < dev->num_tx_queues; i++) { | 1582 | for (i = 0; i < dev->num_tx_queues; i++) { |
1562 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 1583 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); |
1584 | |||
1585 | __netif_tx_lock(txq, cpu); | ||
1563 | netif_tx_stop_queue(txq); | 1586 | netif_tx_stop_queue(txq); |
1587 | __netif_tx_unlock(txq); | ||
1564 | } | 1588 | } |
1565 | netif_tx_unlock_bh(dev); | 1589 | local_bh_enable(); |
1566 | } | 1590 | } |
1567 | 1591 | ||
1568 | static inline void netif_addr_lock(struct net_device *dev) | 1592 | static inline void netif_addr_lock(struct net_device *dev) |