* [net-next 02/11] igb: mark PM functions as __maybe_unused
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Arnd Bergmann, netdev, nhorman, sassmann, jogreene, Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Arnd Bergmann <arnd@arndb.de>
The new wake function is only used by the suspend/resume handlers that
are defined in inside of an #ifdef, which can cause this harmless
warning:
drivers/net/ethernet/intel/igb/igb_main.c:7988:13: warning: 'igb_deliver_wake_packet' defined but not used [-Wunused-function]
Removing the #ifdef, instead using a __maybe_unused annotation
simplifies the code and avoids the warning.
Fixes: b90fa8763560 ("igb: Enable reading of wake up packet")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 1cf74aa4ebd9..2d5bdb1fd37d 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -191,10 +191,7 @@ static int igb_disable_sriov(struct pci_dev *dev);
static int igb_pci_disable_sriov(struct pci_dev *dev);
#endif
-#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
static int igb_suspend(struct device *);
-#endif
static int igb_resume(struct device *);
static int igb_runtime_suspend(struct device *dev);
static int igb_runtime_resume(struct device *dev);
@@ -204,7 +201,6 @@ static const struct dev_pm_ops igb_pm_ops = {
SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume,
igb_runtime_idle)
};
-#endif
static void igb_shutdown(struct pci_dev *);
static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
#ifdef CONFIG_IGB_DCA
@@ -8015,9 +8011,7 @@ static void igb_deliver_wake_packet(struct net_device *netdev)
netif_rx(skb);
}
-#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
-static int igb_suspend(struct device *dev)
+static int __maybe_unused igb_suspend(struct device *dev)
{
int retval;
bool wake;
@@ -8036,9 +8030,8 @@ static int igb_suspend(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
-static int igb_resume(struct device *dev)
+static int __maybe_unused igb_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
@@ -8092,7 +8085,7 @@ static int igb_resume(struct device *dev)
return err;
}
-static int igb_runtime_idle(struct device *dev)
+static int __maybe_unused igb_runtime_idle(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
@@ -8104,7 +8097,7 @@ static int igb_runtime_idle(struct device *dev)
return -EBUSY;
}
-static int igb_runtime_suspend(struct device *dev)
+static int __maybe_unused igb_runtime_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
int retval;
@@ -8124,11 +8117,10 @@ static int igb_runtime_suspend(struct device *dev)
return 0;
}
-static int igb_runtime_resume(struct device *dev)
+static int __maybe_unused igb_runtime_resume(struct device *dev)
{
return igb_resume(dev);
}
-#endif /* CONFIG_PM */
static void igb_shutdown(struct pci_dev *pdev)
{
--
2.12.2
^ permalink raw reply related
* [net-next 01/11] igb: Explicitly select page 0 at initialization
From: Jeff Kirsher @ 2017-06-06 8:57 UTC (permalink / raw)
To: davem
Cc: Matwey V Kornilov, netdev, nhorman, sassmann, jogreene, stable,
Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Matwey V Kornilov <matwey@sai.msu.ru>
The functions igb_read_phy_reg_gs40g/igb_write_phy_reg_gs40g (which were
removed in 2a3cdea) explicitly selected the required page at every phy_reg
access. Currently, igb_get_phy_id_82575 relays on the fact that page 0 is
already selected. The assumption is not fulfilled for my Lex 3I380CW
motherboard with integrated dual i211 based gigabit ethernet. This leads to igb
initialization failure and network interfaces are not working:
igb: Intel(R) Gigabit Ethernet Network Driver - version 5.4.0-k
igb: Copyright (c) 2007-2014 Intel Corporation.
igb: probe of 0000:01:00.0 failed with error -2
igb: probe of 0000:02:00.0 failed with error -2
In order to fix it, we explicitly select page 0 before first access to phy
registers.
See also: https://bugzilla.suse.com/show_bug.cgi?id=1009911
See also: http://www.lex.com.tw/products/pdf/3I380A&3I380CW.pdf
Fixes: 2a3cdea ("igb: Remove GS40G specific defines/functions")
Cc: <stable@vger.kernel.org> # 4.5+
Signed-off-by: Matwey V Kornilov <matwey@sai.msu.ru>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/e1000_82575.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index ee443985581f..4a50870e0fa7 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -257,6 +257,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
}
/* Set phy->phy_addr and phy->id. */
+ igb_write_phy_reg_82580(hw, I347AT4_PAGE_SELECT, 0);
ret_val = igb_get_phy_id_82575(hw);
if (ret_val)
return ret_val;
--
2.12.2
^ permalink raw reply related
* [net-next 05/11] igb: avoid permanent lock of *_PTP_TX_IN_PROGRESS
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Jacob Keller, netdev, nhorman, sassmann, jogreene, Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
The igb driver uses a state bit lock to avoid handling more than one Tx
timestamp request at once. This is required because hardware is limited
to a single set of registers for Tx timestamps.
The state bit lock is not properly cleaned up during
igb_xmit_frame_ring() if the transmit fails such as due to DMA or TSO
failure. In some hardware this results in blocking timestamps until the
service task times out. In other hardware this results in a permanent
lock of the timestamp bit because we never receive an interrupt
indicating the timestamp occurred, since indeed the packet was never
transmitted.
Fix this by checking for DMA and TSO errors in igb_xmit_frame_ring() and
properly cleaning up after ourselves when these occur.
Reported-by: Reported-by: David Mirabito <davidm@metamako.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 2d5bdb1fd37d..fefa46120cbc 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -5197,9 +5197,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
return __igb_maybe_stop_tx(tx_ring, size);
}
-static void igb_tx_map(struct igb_ring *tx_ring,
- struct igb_tx_buffer *first,
- const u8 hdr_len)
+static int igb_tx_map(struct igb_ring *tx_ring,
+ struct igb_tx_buffer *first,
+ const u8 hdr_len)
{
struct sk_buff *skb = first->skb;
struct igb_tx_buffer *tx_buffer;
@@ -5310,7 +5310,7 @@ static void igb_tx_map(struct igb_ring *tx_ring,
*/
mmiowb();
}
- return;
+ return 0;
dma_error:
dev_err(tx_ring->dev, "TX DMA map failed\n");
@@ -5341,6 +5341,8 @@ static void igb_tx_map(struct igb_ring *tx_ring,
tx_buffer->skb = NULL;
tx_ring->next_to_use = i;
+
+ return -1;
}
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
@@ -5406,13 +5408,24 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
else if (!tso)
igb_tx_csum(tx_ring, first);
- igb_tx_map(tx_ring, first, hdr_len);
+ if (igb_tx_map(tx_ring, first, hdr_len))
+ goto cleanup_tx_tstamp;
return NETDEV_TX_OK;
out_drop:
dev_kfree_skb_any(first->skb);
first->skb = NULL;
+cleanup_tx_tstamp:
+ if (unlikely(tx_flags & IGB_TX_FLAGS_TSTAMP)) {
+ struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
+
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
+ if (adapter->hw.mac.type == e1000_82576)
+ cancel_work_sync(&adapter->ptp_tx_work);
+ clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
+ }
return NETDEV_TX_OK;
}
--
2.12.2
^ permalink raw reply related
* [net-next 03/11] e1000e: fix race condition around skb_tstamp_tx()
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Jacob Keller, netdev, nhorman, sassmann, jogreene, Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
The e1000e driver and related hardware has a limitation on Tx PTP
packets which requires we limit to timestamping a single packet at once.
We do this by verifying that we never request a new Tx timestamp while
we still have a tx_hwtstamp_skb pointer.
Unfortunately the driver suffers from a race condition around this. The
tx_hwtstamp_skb pointer is not set to NULL until after skb_tstamp_tx()
is called. This function notifies the stack and applications of a new
timestamp. Even a well behaved application that only sends a new request
when the first one is finished might be woken up and possibly send
a packet before we can free the timestamp in the driver again. The
result is that we needlessly ignore some Tx timestamp requests in this
corner case.
Fix this by assigning the tx_hwtstamp_skb pointer prior to calling
skb_tstamp_tx() and use a temporary pointer to hold the timestamped skb
until that function finishes. This ensures that the application is not
woken up until the driver is ready to begin timestamping a new packet.
This ensures that well behaved applications do not accidentally race
with condition to skip Tx timestamps. Obviously an application which
sends multiple Tx timestamp requests at once will still only timestamp
one packet at a time. Unfortunately there is nothing we can do about
this.
Reported-by: David Mirabito <davidm@metamako.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000e/netdev.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 6ed3bc419b96..96257349a1b8 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1183,6 +1183,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
struct e1000_hw *hw = &adapter->hw;
if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
+ struct sk_buff *skb = adapter->tx_hwtstamp_skb;
struct skb_shared_hwtstamps shhwtstamps;
u64 txstmp;
@@ -1191,9 +1192,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
- skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
- dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+ /* Clear the global tx_hwtstamp_skb pointer and force writes
+ * prior to notifying the stack of a Tx timestamp.
+ */
adapter->tx_hwtstamp_skb = NULL;
+ wmb(); /* force write prior to skb_tstamp_tx */
+
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
} else if (time_after(jiffies, adapter->tx_hwtstamp_start
+ adapter->tx_timeout_factor * HZ)) {
dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
--
2.12.2
^ permalink raw reply related
* [net-next 04/11] igb: fix race condition with PTP_TX_IN_PROGRESS bits
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Jacob Keller, netdev, nhorman, sassmann, jogreene, Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
Hardware related to the igb driver has a limitation of only handling one
Tx timestamp at a time. Thus, the driver uses a state bit lock to
enforce that only one timestamp request is honored at a time.
Unfortunately this suffers from a simple race condition. The bit lock is
not cleared until after skb_tstamp_tx() is called notifying the stack of
a new Tx timestamp. Even a well behaved application which sends only one
timestamp request at once and waits for a response might wake up and
send a new packet before the bit lock is cleared. This results in
needlessly dropping some Tx timestamp requests.
We can fix this by unlocking the state bit as soon as we read the
Timestamp register, as this is the first point at which it is safe to
unlock.
To avoid issues with the skb pointer, we'll use a copy of the pointer
and set the global variable in the driver structure to NULL first. This
ensures that the next timestamp request does not modify our local copy
of the skb pointer.
This ensures that well behaved applications do not accidentally race
with the unlock bit. Obviously an application which sends multiple Tx
timestamp requests at once will still only timestamp one packet at
a time. Unfortunately there is nothing we can do about this.
Reported-by: David Mirabito <davidm@metamako.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_ptp.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index d333d6d80194..ffd2c7c36d9c 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -721,6 +721,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
**/
static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
{
+ struct sk_buff *skb = adapter->ptp_tx_skb;
struct e1000_hw *hw = &adapter->hw;
struct skb_shared_hwtstamps shhwtstamps;
u64 regval;
@@ -748,10 +749,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
shhwtstamps.hwtstamp =
ktime_add_ns(shhwtstamps.hwtstamp, adjust);
- skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
- dev_kfree_skb_any(adapter->ptp_tx_skb);
+ /* Clear the lock early before calling skb_tstamp_tx so that
+ * applications are not woken up before the lock bit is clear. We use
+ * a copy of the skb pointer to ensure other threads can't change it
+ * while we're notifying the stack.
+ */
adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
+
+ /* Notify the stack and free the skb after we've unlocked */
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
}
/**
--
2.12.2
^ permalink raw reply related
* [net-next 06/11] e1000e: add statistic indicating number of skipped Tx timestamps
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Jacob Keller, netdev, nhorman, sassmann, jogreene, Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
The e1000e driver can only handle one Tx timestamp request at a time.
This means it is possible for an application timestamp request to be
ignored.
There is no easy way for an administrator to determine if this occurred.
Add a new statistic which tracks this, tx_hwtstamp_skipped.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000e/e1000.h | 1 +
drivers/net/ethernet/intel/e1000e/ethtool.c | 1 +
drivers/net/ethernet/intel/e1000e/netdev.c | 17 ++++++++++-------
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index c7c994eb410e..98e68888abb1 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -268,6 +268,7 @@ struct e1000_adapter {
u32 tx_fifo_size;
u32 tx_dma_failed;
u32 tx_hwtstamp_timeouts;
+ u32 tx_hwtstamp_skipped;
/* Rx */
bool (*clean_rx)(struct e1000_ring *ring, int *work_done,
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index e23dbd9190d6..c658f6ebf7cb 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -105,6 +105,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("uncorr_ecc_errors", uncorr_errors),
E1000_STAT("corr_ecc_errors", corr_errors),
E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+ E1000_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
};
#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 96257349a1b8..fc1d92ca3ea2 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5867,13 +5867,16 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
nr_frags);
if (count) {
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
- (adapter->flags & FLAG_HAS_HW_TIMESTAMP) &&
- !adapter->tx_hwtstamp_skb) {
- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
- tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
- adapter->tx_hwtstamp_skb = skb_get(skb);
- adapter->tx_hwtstamp_start = jiffies;
- schedule_work(&adapter->tx_hwtstamp_work);
+ (adapter->flags & FLAG_HAS_HW_TIMESTAMP)) {
+ if (!adapter->tx_hwtstamp_skb) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
+ adapter->tx_hwtstamp_skb = skb_get(skb);
+ adapter->tx_hwtstamp_start = jiffies;
+ schedule_work(&adapter->tx_hwtstamp_work);
+ } else {
+ adapter->tx_hwtstamp_skipped++;
+ }
}
skb_tx_timestamp(skb);
--
2.12.2
^ permalink raw reply related
* [net-next 07/11] igb: add statistic indicating number of skipped Tx timestamps
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Jacob Keller, netdev, nhorman, sassmann, jogreene, Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
The igb driver can only handle one Tx timestamp request at a time.
This means it is possible for an application timestamp request to be
ignored.
There is no easy way for an administrator to determine if this occurred.
Add a new statistic which tracks this, tx_hwtstamp_skipped.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 1 +
drivers/net/ethernet/intel/igb/igb_ethtool.c | 1 +
drivers/net/ethernet/intel/igb/igb_main.c | 2 ++
3 files changed, 4 insertions(+)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index bf9bf9056d0c..be35edcf6b08 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -563,6 +563,7 @@ struct igb_adapter {
struct cyclecounter cc;
struct timecounter tc;
u32 tx_hwtstamp_timeouts;
+ u32 tx_hwtstamp_skipped;
u32 rx_hwtstamp_cleared;
bool pps_sys_wrap_on;
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 0efb62db6efd..8730f7cbce68 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -90,6 +90,7 @@ static const struct igb_stats igb_gstrings_stats[] = {
IGB_STAT("os2bmc_tx_by_host", stats.o2bspc),
IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc),
IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+ IGB_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
};
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index fefa46120cbc..06b81a609fa0 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -5388,6 +5388,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
adapter->ptp_tx_start = jiffies;
if (adapter->hw.mac.type == e1000_82576)
schedule_work(&adapter->ptp_tx_work);
+ } else {
+ adapter->tx_hwtstamp_skipped++;
}
}
--
2.12.2
^ permalink raw reply related
* [net-next 11/11] e1000e: use disable_hardirq() also for MSIX vectors in e1000_netpoll()
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem
Cc: Konstantin Khlebnikov, netdev, nhorman, sassmann, jogreene,
Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Replace disable_irq() which waits for threaded irq handlers with
disable_hardirq() which waits only for hardirq part.
Fixes: 311191297125 ("e1000: use disable_hardirq() for e1000_netpoll()")
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000e/netdev.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index fc1d92ca3ea2..e1d46c11cb61 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -6743,20 +6743,20 @@ static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data)
vector = 0;
msix_irq = adapter->msix_entries[vector].vector;
- disable_irq(msix_irq);
- e1000_intr_msix_rx(msix_irq, netdev);
+ if (disable_hardirq(msix_irq))
+ e1000_intr_msix_rx(msix_irq, netdev);
enable_irq(msix_irq);
vector++;
msix_irq = adapter->msix_entries[vector].vector;
- disable_irq(msix_irq);
- e1000_intr_msix_tx(msix_irq, netdev);
+ if (disable_hardirq(msix_irq))
+ e1000_intr_msix_tx(msix_irq, netdev);
enable_irq(msix_irq);
vector++;
msix_irq = adapter->msix_entries[vector].vector;
- disable_irq(msix_irq);
- e1000_msix_other(msix_irq, netdev);
+ if (disable_hardirq(msix_irq))
+ e1000_msix_other(msix_irq, netdev);
enable_irq(msix_irq);
}
--
2.12.2
^ permalink raw reply related
* [net-next 08/11] igb: check for Tx timestamp timeouts during watchdog
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Jacob Keller, netdev, nhorman, sassmann, jogreene, Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
The igb driver has logic to handle only one Tx timestamp at a time,
using a state bit lock to avoid multiple requests at once.
It may be possible, if incredibly unlikely, that a Tx timestamp event is
requested but never completes. Since we use an interrupt scheme to
determine when the Tx timestamp occurred we would never clear the state
bit in this case.
Add an igb_ptp_tx_hang() function similar to the already existing
igb_ptp_rx_hang() function. This function runs in the watchdog routine
and makes sure we eventually recover from this case instead of
permanently disabling Tx timestamps.
Note: there is no currently known way to cause this without hacking the
driver code to force it.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 1 +
drivers/net/ethernet/intel/igb/igb_main.c | 1 +
drivers/net/ethernet/intel/igb/igb_ptp.c | 29 +++++++++++++++++++++++++++++
3 files changed, 31 insertions(+)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index be35edcf6b08..ff4d9073781a 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -677,6 +677,7 @@ void igb_ptp_stop(struct igb_adapter *adapter);
void igb_ptp_reset(struct igb_adapter *adapter);
void igb_ptp_suspend(struct igb_adapter *adapter);
void igb_ptp_rx_hang(struct igb_adapter *adapter);
+void igb_ptp_tx_hang(struct igb_adapter *adapter);
void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb);
void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va,
struct sk_buff *skb);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 06b81a609fa0..0a333509d5d5 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -4722,6 +4722,7 @@ static void igb_watchdog_task(struct work_struct *work)
igb_spoof_check(adapter);
igb_ptp_rx_hang(adapter);
+ igb_ptp_tx_hang(adapter);
/* Check LVMMC register on i350/i354 only */
if ((adapter->hw.mac.type == e1000_i350) ||
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index ffd2c7c36d9c..841c2a083349 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -712,6 +712,35 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
}
/**
+ * igb_ptp_tx_hang - detect error case where Tx timestamp never finishes
+ * @adapter: private network adapter structure
+ */
+void igb_ptp_tx_hang(struct igb_adapter *adapter)
+{
+ bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
+ IGB_PTP_TX_TIMEOUT);
+
+ if (!adapter->ptp_tx_skb)
+ return;
+
+ if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state))
+ return;
+
+ /* If we haven't received a timestamp within the timeout, it is
+ * reasonable to assume that it will never occur, so we can unlock the
+ * timestamp bit when this occurs.
+ */
+ if (timeout) {
+ cancel_work_sync(&adapter->ptp_tx_work);
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
+ clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
+ adapter->tx_hwtstamp_timeouts++;
+ dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n");
+ }
+}
+
+/**
* igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
* @adapter: Board private structure.
*
--
2.12.2
^ permalink raw reply related
* [net-next 09/11] igb: Remove useless argument
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Benjamin Poirier, netdev, nhorman, sassmann, jogreene,
Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Benjamin Poirier <bpoirier@suse.com>
Given that all callers of igb_update_stats() pass the same two arguments:
(adapter, &adapter->stats64), the second argument can be removed.
Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 2 +-
drivers/net/ethernet/intel/igb/igb_ethtool.c | 2 +-
drivers/net/ethernet/intel/igb/igb_main.c | 10 +++++-----
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index ff4d9073781a..06ffb2bc713e 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -667,7 +667,7 @@ void igb_setup_tctl(struct igb_adapter *);
void igb_setup_rctl(struct igb_adapter *);
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *);
void igb_alloc_rx_buffers(struct igb_ring *, u16);
-void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *);
+void igb_update_stats(struct igb_adapter *);
bool igb_has_link(struct igb_adapter *adapter);
void igb_set_ethtool_ops(struct net_device *);
void igb_power_up_link(struct igb_adapter *);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 8730f7cbce68..d06a8db514d4 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2316,7 +2316,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
char *p;
spin_lock(&adapter->stats64_lock);
- igb_update_stats(adapter, net_stats);
+ igb_update_stats(adapter);
for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
p = (char *)adapter + igb_gstrings_stats[i].stat_offset;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 0a333509d5d5..7e433344a13c 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1818,7 +1818,7 @@ void igb_down(struct igb_adapter *adapter)
/* record the stats before reset*/
spin_lock(&adapter->stats64_lock);
- igb_update_stats(adapter, &adapter->stats64);
+ igb_update_stats(adapter);
spin_unlock(&adapter->stats64_lock);
adapter->link_speed = 0;
@@ -4686,7 +4686,7 @@ static void igb_watchdog_task(struct work_struct *work)
}
spin_lock(&adapter->stats64_lock);
- igb_update_stats(adapter, &adapter->stats64);
+ igb_update_stats(adapter);
spin_unlock(&adapter->stats64_lock);
for (i = 0; i < adapter->num_tx_queues; i++) {
@@ -5499,7 +5499,7 @@ static void igb_get_stats64(struct net_device *netdev,
struct igb_adapter *adapter = netdev_priv(netdev);
spin_lock(&adapter->stats64_lock);
- igb_update_stats(adapter, &adapter->stats64);
+ igb_update_stats(adapter);
memcpy(stats, &adapter->stats64, sizeof(*stats));
spin_unlock(&adapter->stats64_lock);
}
@@ -5548,9 +5548,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
* igb_update_stats - Update the board statistics counters
* @adapter: board private structure
**/
-void igb_update_stats(struct igb_adapter *adapter,
- struct rtnl_link_stats64 *net_stats)
+void igb_update_stats(struct igb_adapter *adapter)
{
+ struct rtnl_link_stats64 *net_stats = &adapter->stats64;
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
u32 reg, mpc;
--
2.12.2
^ permalink raw reply related
* [net-next 10/11] e1000e: Don't return uninitialized stats
From: Jeff Kirsher @ 2017-06-06 8:58 UTC (permalink / raw)
To: davem; +Cc: Benjamin Poirier, netdev, nhorman, sassmann, jogreene,
Jeff Kirsher
In-Reply-To: <20170606085809.78571-1-jeffrey.t.kirsher@intel.com>
From: Benjamin Poirier <bpoirier@suse.com>
Some statistics passed to ethtool are garbage because e1000e_get_stats64()
doesn't write them, for example: tx_heartbeat_errors. This leaks kernel
memory to userspace and confuses users.
Do like ixgbe and use dev_get_stats() which first zeroes out
rtnl_link_stats64.
Fixes: 5944701df90d ("net: remove useless memset's in drivers get_stats64")
Reported-by: Stefan Priebe <s.priebe@profihost.ag>
Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000e/ethtool.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index c658f6ebf7cb..003cbd605799 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -2073,7 +2073,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
pm_runtime_get_sync(netdev->dev.parent);
- e1000e_get_stats64(netdev, &net_stats);
+ dev_get_stats(netdev, &net_stats);
pm_runtime_put_sync(netdev->dev.parent);
--
2.12.2
^ permalink raw reply related
* Re: [PATCH net-next 00/16] nfp: ctrl vNIC
From: Jakub Kicinski @ 2017-06-06 9:09 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, oss-drivers
In-Reply-To: <20170606082336.GB1911@nanopsycho>
On Tue, 6 Jun 2017 10:23:36 +0200, Jiri Pirko wrote:
> Tue, Jun 06, 2017 at 09:21:45AM CEST, kubakici@wp.pl wrote:
> >On Tue, 6 Jun 2017 08:16:10 +0200, Jiri Pirko wrote:
> >> Tue, Jun 06, 2017 at 02:01:41AM CEST, jakub.kicinski@netronome.com wrote:
> >> >Hi!
> >> >
> >> >This series adds the ability to use one vNIC as a control channel
> >> >for passing messages to and from the application firmware. The
> >> >implementation restructures the existing netdev vNIC code to be able
> >> >to deal with nfp_nets with netdev pointer set to NULL. Control vNICs
> >> >are not visible to userspace (other than for dumping ring state), and
> >> >since they don't have netdevs we use a tasklet for RX and simple skb
> >> >list for TX queuing.
> >> >
> >> >Due to special status of the control vNIC we have to reshuffle the
> >> >init code a bit to make sure control vNIC will be fully brought up
> >> >(and therefore communication with app FW can happen) before any netdev
> >> >or port is visible to user space.
> >> >
> >> >FW will designate which vNIC is supposed to be used as control one
> >> >by setting _pf%u_net_ctrl_bar symbol. Some FWs depend on metadata
> >> >being prepended to control message, some prefer to look at queue ID
> >> >to decide that something is a control message. Our implementation
> >> >can cater to both.
> >> >
> >> >First two users of this code will be eBPF maps and flower offloads.
> >>
> >> How do you actually do the configuration from the userspace? I did not
> >> find it in the patches.
> >
> >Yes, there is nothing interesting in those patches, really. It's all
> >internal to the driver. This set basically allows us to dedicate some
> >queue pairs to high-speed communication with the FW (sending commands,
> >populating/dumping eBPF and Flower tables).
> >
> >The eBPF maps and Flower offload patches should follow in coming weeks.
>
> Okay. So you don't let the user to dicide for which purpose (bpf/flowe)
> he wants to use the nic, right?
Yes, right now we just expect the user to drop the FW file he wants
to run into /lib/firmware/netronome. Driver will interrogate the
firmware once loaded to see which "app" it is.
> >> The configuration is asic-wide, should be done by a devlink parent
> >> handle which was introduced for that exact purpose.
> >>
> >> Am I missing something? We need to sync in this. In mlxsw we need to do
> >> some pre-netdev configuraton as well.
> >
> >For programmable NICs we still need to come up with some API for setting
> >the target application/firmware name/adapter mode, but I don't think we
> >have any more fine-grained parameters to set per-device just yet.
> >
> >I was thinking of either devlink, or perhaps, since I'm hearing people
> >want those to be persistent/written into flash, the recent MTD
> >discussion got me wondering if we should just expose the entire flash
> >and teach ethtool to modify the vendor-specific parameter table
> >directly in the flash. That seems like something that could quickly
> >get out of hand, though :S
>
> Yeah, I'm not fan of the mtd exposing some fw internals. I believe that
> for the config like yours (switching the operation mode of nic), we
> should have well defined user api. And since this is per-device, not
> per-netdev, devlink should be the vahicle to carry this.
Well defined API would be nice. Perhaps we will just start with
something very simple and then extend it if need be. E.g. I'm hearing
people would like to select not only the app but also the version of
it... Yes, starting simple is probably the way forward.
> >What were your plans with pre-netdev config?
>
> We need to pass come initial resource division. Generally the consensus
> is to have these options exposed through devlink, let the user configure
> them all and then to have a trigger that would cause driver
> re-orchestration according to the new values. The flow would look like
> this:
>
> -driver loads with defaults, inits hw and instantiates netdevs
> -driver exposes config options via devlink
> -user sets up the options
> -user pushes the "go" trigger
> -upon the trigger command, devlink calls the driver re-init callback
> -driver shuts down the current instances, re-initializes hw,
> re-instantiates the netdevs
>
> Makes sense?
I like the idea of a "go"/apply/reload trigger and extending devlink.
Do you plan on adding a way to persist the settings? I'm concerned NIC
users may want to boot into the right mode once it's set, without
reloads and reconfigs upon boot. Also is there going to be a way to
query the pending/running config? Sounds like we may want to expose
three value sets - persistent/default, running and pending/to be
applied.
^ permalink raw reply
* Re: [PATCH net] net: stmmac: fix completely hung TX when using TSO
From: Alexandre Torgue @ 2017-06-06 9:10 UTC (permalink / raw)
To: Giuseppe CAVALLARO, Niklas Cassel; +Cc: Niklas Cassel, netdev, linux-kernel
In-Reply-To: <53a84a68-5014-7a92-5e78-f9f04aa948c6@st.com>
Hi Guys,
On 06/06/2017 10:00 AM, Giuseppe CAVALLARO wrote:
> Hi Niklas
>
> I get the point and I acked the patch but Alex, please, can you confirm
> that this issue has never seen on your boxes where the TSO has been
> fully tested? The initial development (commit f748be531) introduces
> the following:
> (last_segment) && (buff_size < TSO_MAX_BUFF_SIZE),
I don't remember to have seen this kind of issue in the past but for
sure I agree with this patch.
Acked-by: Alexandre TORGUE <alexandre.torgue@st.com>
> ...
>
> On 6/6/2017 9:25 AM, Niklas Cassel wrote:
>> stmmac_tso_allocator can fail to set the Last Descriptor bit
>> on a descriptor that actually was the last descriptor.
>>
>> This happens when the buffer of the last descriptor ends
>> up having a size of exactly TSO_MAX_BUFF_SIZE.
>>
>> When the IP eventually reaches the next last descriptor,
>> which actually has the bit set, the DMA will hang.
>>
>> When the DMA hangs, we get a tx timeout, however,
>> since stmmac does not do a complete reset of the IP
>> in stmmac_tx_timeout, we end up in a state with
>> completely hung TX.
>>
>> Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
>
> Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
>
>> ---
>> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> index 68a188e74c54..440bea049a7f 100644
>> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> @@ -2723,7 +2723,7 @@ static void stmmac_tso_allocator(struct
>> stmmac_priv *priv, unsigned int des,
>> priv->hw->desc->prepare_tso_tx_desc(desc, 0, buff_size,
>> 0, 1,
>> - (last_segment) && (buff_size < TSO_MAX_BUFF_SIZE),
>> + (last_segment) && (tmp_len <= TSO_MAX_BUFF_SIZE),
>> 0, 0);
>> tmp_len -= TSO_MAX_BUFF_SIZE;
>
> Regards
> Peppe
>
>
^ permalink raw reply
* RE: [patch net-next 3/3] mlxsw: spectrum_router: Align RIF index allocation with existing code
From: David Laight @ 2017-06-06 9:11 UTC (permalink / raw)
To: 'Jiri Pirko', netdev@vger.kernel.org
Cc: davem@davemloft.net, idosch@mellanox.com, petrm@mellanox.com,
mlxsw@mellanox.com
In-Reply-To: <20170604145340.14447-4-jiri@resnulli.us>
From: Jiri Pirko
> Sent: 04 June 2017 15:54
> The way we usually allocate an index is by letting the allocation
> function return an error instead of an invalid index.
...
> -static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp)
> +static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index)
You typically get much better code from returning an invalid index.
This is why PTR_ERR() exists.
David
^ permalink raw reply
* Re: [PATCH net-next 00/16] nfp: ctrl vNIC
From: Jiri Pirko @ 2017-06-06 9:17 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, oss-drivers
In-Reply-To: <20170606020945.05a9bcc5@cakuba.netronome.com>
Tue, Jun 06, 2017 at 11:09:45AM CEST, kubakici@wp.pl wrote:
>On Tue, 6 Jun 2017 10:23:36 +0200, Jiri Pirko wrote:
>> Tue, Jun 06, 2017 at 09:21:45AM CEST, kubakici@wp.pl wrote:
>> >On Tue, 6 Jun 2017 08:16:10 +0200, Jiri Pirko wrote:
>> >> Tue, Jun 06, 2017 at 02:01:41AM CEST, jakub.kicinski@netronome.com wrote:
>> >> >Hi!
>> >> >
>> >> >This series adds the ability to use one vNIC as a control channel
>> >> >for passing messages to and from the application firmware. The
>> >> >implementation restructures the existing netdev vNIC code to be able
>> >> >to deal with nfp_nets with netdev pointer set to NULL. Control vNICs
>> >> >are not visible to userspace (other than for dumping ring state), and
>> >> >since they don't have netdevs we use a tasklet for RX and simple skb
>> >> >list for TX queuing.
>> >> >
>> >> >Due to special status of the control vNIC we have to reshuffle the
>> >> >init code a bit to make sure control vNIC will be fully brought up
>> >> >(and therefore communication with app FW can happen) before any netdev
>> >> >or port is visible to user space.
>> >> >
>> >> >FW will designate which vNIC is supposed to be used as control one
>> >> >by setting _pf%u_net_ctrl_bar symbol. Some FWs depend on metadata
>> >> >being prepended to control message, some prefer to look at queue ID
>> >> >to decide that something is a control message. Our implementation
>> >> >can cater to both.
>> >> >
>> >> >First two users of this code will be eBPF maps and flower offloads.
>> >>
>> >> How do you actually do the configuration from the userspace? I did not
>> >> find it in the patches.
>> >
>> >Yes, there is nothing interesting in those patches, really. It's all
>> >internal to the driver. This set basically allows us to dedicate some
>> >queue pairs to high-speed communication with the FW (sending commands,
>> >populating/dumping eBPF and Flower tables).
>> >
>> >The eBPF maps and Flower offload patches should follow in coming weeks.
>>
>> Okay. So you don't let the user to dicide for which purpose (bpf/flowe)
>> he wants to use the nic, right?
>
>Yes, right now we just expect the user to drop the FW file he wants
>to run into /lib/firmware/netronome. Driver will interrogate the
>firmware once loaded to see which "app" it is.
>
>> >> The configuration is asic-wide, should be done by a devlink parent
>> >> handle which was introduced for that exact purpose.
>> >>
>> >> Am I missing something? We need to sync in this. In mlxsw we need to do
>> >> some pre-netdev configuraton as well.
>> >
>> >For programmable NICs we still need to come up with some API for setting
>> >the target application/firmware name/adapter mode, but I don't think we
>> >have any more fine-grained parameters to set per-device just yet.
>> >
>> >I was thinking of either devlink, or perhaps, since I'm hearing people
>> >want those to be persistent/written into flash, the recent MTD
>> >discussion got me wondering if we should just expose the entire flash
>> >and teach ethtool to modify the vendor-specific parameter table
>> >directly in the flash. That seems like something that could quickly
>> >get out of hand, though :S
>>
>> Yeah, I'm not fan of the mtd exposing some fw internals. I believe that
>> for the config like yours (switching the operation mode of nic), we
>> should have well defined user api. And since this is per-device, not
>> per-netdev, devlink should be the vahicle to carry this.
>
>Well defined API would be nice. Perhaps we will just start with
>something very simple and then extend it if need be. E.g. I'm hearing
>people would like to select not only the app but also the version of
>it... Yes, starting simple is probably the way forward.
>
>> >What were your plans with pre-netdev config?
>>
>> We need to pass come initial resource division. Generally the consensus
>> is to have these options exposed through devlink, let the user configure
>> them all and then to have a trigger that would cause driver
>> re-orchestration according to the new values. The flow would look like
>> this:
>>
>> -driver loads with defaults, inits hw and instantiates netdevs
>> -driver exposes config options via devlink
>> -user sets up the options
>> -user pushes the "go" trigger
>> -upon the trigger command, devlink calls the driver re-init callback
>> -driver shuts down the current instances, re-initializes hw,
>> re-instantiates the netdevs
>>
>> Makes sense?
>
>I like the idea of a "go"/apply/reload trigger and extending devlink.
>Do you plan on adding a way to persist the settings? I'm concerned NIC
>users may want to boot into the right mode once it's set, without
>reloads and reconfigs upon boot. Also is there going to be a way to
>query the pending/running config? Sounds like we may want to expose
>three value sets - persistent/default, running and pending/to be
>applied.
I don't think it is a good idea to introduce any kind of configuration
persistency in HW. I believe that user is the master and he has all
needed info. He can store it persistently, but it is up to him.
So basicaly during boot, we need the devlink configuration to happen
early on, before the netdevices get configured. udev? Not sure how
exactly to do this. Have to ask around :)
^ permalink raw reply
* Re: [PATCH v2] xfrm: fix xfrm_dev_event() missing when compile without CONFIG_XFRM_OFFLOAD
From: Hangbin Liu @ 2017-06-06 9:26 UTC (permalink / raw)
To: Steffen Klassert; +Cc: netdev, Guy Shapiro, David Miller
In-Reply-To: <20170606080658.GO2631@secunet.com>
On Tue, Jun 06, 2017 at 10:06:58AM +0200, Steffen Klassert wrote:
> On Thu, Jun 01, 2017 at 02:57:56PM +0800, Hangbin Liu wrote:
> > In commit d77e38e612a0 ("xfrm: Add an IPsec hardware offloading API") we
> > make xfrm_device.o only compiled when enable option CONFIG_XFRM_OFFLOAD.
> > But this will make xfrm_dev_event() missing if we only enable default XFRM
> > options.
> >
> > Then if we set down and unregister an interface with IPsec on it.
>
> You should not be able to register an interface with IPsec offload
> without CONFIG_XFRM_OFFLOAD.
Yes, I mean when compile with default CONFIG_XFRM, the xfrm_dev_event() ->
xfrm_dev_down() -> xfrm_garbage_collect() will missing.
>
> > there
> > will no xfrm_garbage_collect(), which will cause dev usage count hold and
> > get error like:
> >
> > unregister_netdevice: waiting for <dev> to become free. Usage count = 4
>
> Can you explain how to reproduce this?
>
Sure, I didn't try physical drivers, just test latest net-next with
bridge/bonding and could reproduce it everytime.
```
# cat rep.sh
#!/bin/bash
iface=$1
src=$2
dst=$3
run=$4
brctl addbr br0
brctl addif br0 ${iface}
ip link set ${iface} up
ip link set br0 up
ip addr add ${src}/24 dev br0
ip xfrm state flush && ip xfrm policy flush
ip xfrm state add src ${src} dst ${dst} spi 1000 proto esp enc des3_ede _I_want_to_have_chicken_ auth sha1 beef_fish_pork_salad mode transport
ip xfrm state add src ${dst} dst ${src} spi 1000 proto esp enc des3_ede _I_want_to_have_chicken_ auth sha1 beef_fish_pork_salad mode transport
ip xfrm policy add src ${src} dst ${dst} dir out tmpl proto esp spi 1000 mode transport
ip xfrm policy add src ${dst} dst ${src} dir in tmpl proto esp spi 1000 mode transport
if [ "$run" ]; then
sleep 1
ping ${dst} -c 4
ip link set br0 down
ip link del br0
fi
```
On host A run : # ./rep.sh eth1 192.168.1.1 192.168.1.2
On host B run : # ./rep.sh eth1 192.168.1.2 192.168.1.1 run
Then we will see error like
kernel:unregister_netdevice: waiting for br0 to become free. Usage count = 3
Thanks
Hangbin
^ permalink raw reply
* RE: [PATCH net-next 00/16] nfp: ctrl vNIC
From: Mintz, Yuval @ 2017-06-06 9:35 UTC (permalink / raw)
To: Jiri Pirko, Jakub Kicinski
Cc: netdev@vger.kernel.org, oss-drivers@netronome.com
In-Reply-To: <20170606091757.GC1911@nanopsycho>
> >> >What were your plans with pre-netdev config?
> >>
> >> We need to pass come initial resource division. Generally the
> >> consensus is to have these options exposed through devlink, let the
> >> user configure them all and then to have a trigger that would cause
> >> driver re-orchestration according to the new values. The flow would
> >> look like
> >> this:
> >>
> >> -driver loads with defaults, inits hw and instantiates netdevs
> >> -driver exposes config options via devlink -user sets up the options
> >> -user pushes the "go" trigger -upon the trigger command, devlink
> >> calls the driver re-init callback -driver shuts down the current
> >> instances, re-initializes hw, re-instantiates the netdevs
> >>
> >> Makes sense?
> >
> >I like the idea of a "go"/apply/reload trigger and extending devlink.
> >Do you plan on adding a way to persist the settings? I'm concerned NIC
> >users may want to boot into the right mode once it's set, without
> >reloads and reconfigs upon boot. Also is there going to be a way to
> >query the pending/running config? Sounds like we may want to expose
> >three value sets - persistent/default, running and pending/to be
> >applied.
> I don't think it is a good idea to introduce any kind of configuration
> persistency in HW. I believe that user is the master and he has all needed
> info. He can store it persistently, but it is up to him.
>
> So basicaly during boot, we need the devlink configuration to happen early
> on, before the netdevices get configured. udev? Not sure how exactly to do
> this. Have to ask around :)
Thinking about use cases where we'd want information available at probe time,
it might have been even better to have it separated from the netdevice,
e.g., providing clients with node to configure (generic?) information on top of
their PCI nodes.
^ permalink raw reply
* Re: [PATCH] ravb: Fix use-after-free on `ifconfig eth0 down`
From: Sergei Shtylyov @ 2017-06-06 9:35 UTC (permalink / raw)
To: Eugeniu Rosca, davem, horms+renesas, kazuya.mizuguchi.ks
Cc: netdev, linux-renesas-soc
In-Reply-To: <20170605220810.3933-1-erosca@de.adit-jv.com>
Hello!
On 6/6/2017 1:08 AM, Eugeniu Rosca wrote:
> Commit a47b70ea86bd ("ravb: unmap descriptors when freeing rings") has
> introduced the issue seen in [1] reproduced on H3ULCB board.
>
> Fix this by relocating the RX skb ringbuffer free operation, so that
> swiotlb page unmapping can be done first. Freeing of aligned TX buffers
> is not relevant to the issue seen in [1]. Still, reposition TX free
> calls as well, to have all kfree() operations performed consistently
> _after_ dma_unmap_*()/dma_free_*().
Perhaps it's a material of a separate cleanup patch?
> [1] Console screenshot with the problem reproduced:
>
> salvator-x login: root
> root@salvator-x:~# ifconfig eth0 up
> Micrel KSZ9031 Gigabit PHY e6800000.ethernet-ffffffff:00: \
> attached PHY driver [Micrel KSZ9031 Gigabit PHY] \
> (mii_bus:phy_addr=e6800000.ethernet-ffffffff:00, irq=235)
> IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
> root@salvator-x:~#
> root@salvator-x:~# ifconfig eth0 down
> ==================================================================
> BUG: KASAN: use-after-free in swiotlb_tbl_unmap_single+0xc4/0x35c
> Write of size 1538 at addr ffff8006d884f780 by task ifconfig/1649
>
> CPU: 0 PID: 1649 Comm: ifconfig Not tainted 4.12.0-rc4-00004-g112eb07287d1 #32
> Hardware name: Renesas H3ULCB board based on r8a7795 (DT)
> Call trace:
> [<ffff20000808f11c>] dump_backtrace+0x0/0x3a4
> [<ffff20000808f4d4>] show_stack+0x14/0x1c
> [<ffff20000865970c>] dump_stack+0xf8/0x150
> [<ffff20000831f8b0>] print_address_description+0x7c/0x330
> [<ffff200008320010>] kasan_report+0x2e0/0x2f4
> [<ffff20000831eac0>] check_memory_region+0x20/0x14c
> [<ffff20000831f054>] memcpy+0x48/0x68
> [<ffff20000869ed50>] swiotlb_tbl_unmap_single+0xc4/0x35c
> [<ffff20000869fcf4>] unmap_single+0x90/0xa4
> [<ffff20000869fd14>] swiotlb_unmap_page+0xc/0x14
> [<ffff2000080a2974>] __swiotlb_unmap_page+0xcc/0xe4
> [<ffff2000088acdb8>] ravb_ring_free+0x514/0x870
> [<ffff2000088b25dc>] ravb_close+0x288/0x36c
> [<ffff200008aaf8c4>] __dev_close_many+0x14c/0x174
> [<ffff200008aaf9b4>] __dev_close+0xc8/0x144
> [<ffff200008ac2100>] __dev_change_flags+0xd8/0x194
> [<ffff200008ac221c>] dev_change_flags+0x60/0xb0
> [<ffff200008ba2dec>] devinet_ioctl+0x484/0x9d4
> [<ffff200008ba7b78>] inet_ioctl+0x190/0x194
> [<ffff200008a78c44>] sock_do_ioctl+0x78/0xa8
> [<ffff200008a7a128>] sock_ioctl+0x110/0x3c4
> [<ffff200008365a70>] vfs_ioctl+0x90/0xa0
> [<ffff200008365dbc>] do_vfs_ioctl+0x148/0xc38
> [<ffff2000083668f0>] SyS_ioctl+0x44/0x74
> [<ffff200008083770>] el0_svc_naked+0x24/0x28
>
> The buggy address belongs to the page:
> page:ffff7e001b6213c0 count:0 mapcount:0 mapping: (null) index:0x0
> flags: 0x4000000000000000()
> raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff
> raw: 0000000000000000 ffff7e001b6213e0 0000000000000000 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff8006d884f680: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ffff8006d884f700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>> ffff8006d884f780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ^
> ffff8006d884f800: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ffff8006d884f880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ==================================================================
> Disabling lock debugging due to kernel taint
> root@salvator-x:~#
>
> Fixes: a47b70ea86bd ("ravb: unmap descriptors when freeing rings")
> Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
[...]
Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
MBR, Sergei
^ permalink raw reply
* Re: [PATCH] of_mdio: Fix broken PHY IRQ in case of probe deferral
From: Geert Uytterhoeven @ 2017-06-06 9:43 UTC (permalink / raw)
To: Florian Fainelli
Cc: Andrew Lunn, Geert Uytterhoeven, Rob Herring, Frank Rowand,
Thomas Petazzoni, Sergei Shtylyov, netdev@vger.kernel.org,
devicetree@vger.kernel.org, Linux-Renesas,
linux-kernel@vger.kernel.org
In-Reply-To: <CAMuHMdWWfaP8=H7H+UzrmOYpydi2mGLFGzuk9FQWJtEOug6u5g@mail.gmail.com>
Hi Florian,
On Tue, May 23, 2017 at 11:36 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> On Fri, May 19, 2017 at 12:21 AM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 05/18/2017 01:36 PM, Geert Uytterhoeven wrote:
>>> On Thu, May 18, 2017 at 9:34 PM, Andrew Lunn <andrew@lunn.ch> wrote:
>>>>>> This most certainly works fine in the simple case where you have one PHY
>>>>>> hanging off the MDIO bus, now what happens if you have several?
>>>>>>
>>>>>> Presumably, the first PHY that returns EPROBE_DEFER will make the entire
>>>>>> bus registration return EPROB_DEFER as well, and so on, and so forth,
>>>>>> but I am not sure if we will be properly unwinding the successful
>>>>>> registration of PHYs that either don't have an interrupt, or did not
>>>>>> return EPROBE_DEFER.
>>>>>>
>>>>>> It should be possible to mimic this behavior by using the fixed PHY, and
>>>>>> possibly the dsa_loop.c driver which would create 4 ports, expecting 4
>>>>>> fixed PHYs to be present.
>>>>>
>>>>> mdiobus_unregister(), called from of_mdiobus_register() on failure,
>>>>> should do the unwinding, right?
>>>>>
>>>>> And when the driver is reprobed, all PHYs are reprobed, until they all
>>>>> succeed.
>>>>
>>>> That is the theory. I looked at that while reviewing the patch. But
>>>> this has probably not been tested in anger. It would be good to test
>>>> this properly, with not just the first PHY returning -EPROBE_DEFER, to
>>>> really test the unwind.
>>>
>>> Unfortunately I don't have a board with multiple PHYs, so I cannot test
>>> that case.
>
> I tried adding a few dummy PHYs in DT, but that didn't work.
>
> So how can we proceed?
>
> I think the only way my patch can cause issues is because some systems
> may rely on EPROBE_DEFER errors being ignored.
>
>>> Does unbinding/rebinding a network driver with multiple PHYs currently
>>> work? Or module unload/reload?
>>
>> Usually there is a strict 1:1 mapping between a network device (not
>> driver) and a PHY device, switch drivers however, would have multiple
>> PHYs (one per port, aka net_deice).
>>
>> NB: binding and unbinding of PHYs is pretty broken at the moment though,
>> because there is a complete disconnect between what the Ethernet MAC
>> expects, and the state in which the PHY is. I had some patches to fix
>> that, but this turned out to be playing whack-a-mole which I typically
>> suck at.
>
> I didn't mean unbinding the PHY, but the network device.
> Don't you have the same issue with the state of PHYs as left by the bootloader?
Anyone who can test the behavior on an Ethernet device with multiple PHYs,
e.g. by faking an -EPROBE_DEFER somewhere in the middle?
I'd like to get this issue fixed in v4.13, to avoid a regression when migrating
several systems to a new and better clock driver in v4.14, which will trigger
EPROBE_DEFER.
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH net-next] bpf, arm64: implement jiting of BPF_XADD
From: Daniel Borkmann @ 2017-06-06 9:50 UTC (permalink / raw)
To: Will Deacon; +Cc: davem, zlim.lnx, netdev, linux-arm-kernel, ast, peterz
In-Reply-To: <20170602120212.GF6371@arm.com>
Hi Will,
(Sorry for the late reply, was offline for the last 6 days.)
> On Mon, May 01, 2017 at 02:57:20AM +0200, Daniel Borkmann wrote:
>> This work adds BPF_XADD for BPF_W/BPF_DW to the arm64 JIT and therefore
>> completes JITing of all BPF instructions, meaning we can thus also remove
>> the 'notyet' label and do not need to fall back to the interpreter when
>> BPF_XADD is used in a program!
>>
>> This now also brings arm64 JIT in line with x86_64, s390x, ppc64, sparc64,
>> where all current eBPF features are supported.
>>
>> BPF_W example from test_bpf:
>>
>> .u.insns_int = {
>> BPF_ALU32_IMM(BPF_MOV, R0, 0x12),
>> BPF_ST_MEM(BPF_W, R10, -40, 0x10),
>> BPF_STX_XADD(BPF_W, R10, R0, -40),
>> BPF_LDX_MEM(BPF_W, R0, R10, -40),
>> BPF_EXIT_INSN(),
>> },
>>
>> [...]
>> 00000020: 52800247 mov w7, #0x12 // #18
>> 00000024: 928004eb mov x11, #0xffffffffffffffd8 // #-40
>> 00000028: d280020a mov x10, #0x10 // #16
>> 0000002c: b82b6b2a str w10, [x25,x11]
>> // start of xadd mapping:
>> 00000030: 928004ea mov x10, #0xffffffffffffffd8 // #-40
>> 00000034: 8b19014a add x10, x10, x25
>> 00000038: f9800151 prfm pstl1strm, [x10]
>> 0000003c: 885f7d4b ldxr w11, [x10]
>> 00000040: 0b07016b add w11, w11, w7
>> 00000044: 880b7d4b stxr w11, w11, [x10]
>
> This form of STXR (where s == t) is CONSTRAINED UNPREDICTABLE per the
> architecture; you need to use separate registers for the data and the
> status flag. You might also be interested in the atomic instructions
Thanks! I tried to find some information on this in the reference
guide, but seems I must have overlooked something; should have been
conservative instead. I will send a fix for it later today.
> introduced in ARMv8.1, which includes the LDADD instruction. You can
> check elf_hwcap & HWCAP_ATOMICS to see if it's supported.
Will take a look on this as well, thanks for letting me know.
> Also, did we get a conclusion on the barrier semantics for this? Currently
> you don't have any here: is that ok?
As a basis I took the disasm back then for the atomic_add() /
atomic64_add(), which, iirc, was mapping to ATOMIC_OP() in
atomic_ll_sc.h. This should be equivalent to what the interpreter
does in __bpf_prog_run() for the insns BPF_STX | BPF_XADD | BPF_W
and BPF_STX | BPF_XADD | BPF_DW.
Thanks,
Daniel
^ permalink raw reply
* [PATCH net-next 0/4] rxrpc: Support service upgrade
From: David Howells @ 2017-06-06 9:54 UTC (permalink / raw)
To: netdev; +Cc: dhowells, linux-afs, linux-kernel
Here's a set of patches that allow AF_RXRPC to support the AuriStor service
upgrade facility. This allows the server to change the service ID
requested to an upgraded service if the client requests it upon the
initiation of a connection.
This is used by the AuriStor AFS-compatible servers to implement IPv6
handling and improved facilities by providing improved volume location,
volume, protection, file and cache management services. Note that certain
parts of the AFS protocol carry hard-coded IPv4 addresses.
The reason AuriStor does it this way is that probing the improved service
ID first will not incur an ABORT or any other response on some servers if
the server is not listening on it - and so one have to employ a timeout.
This is implemented in the server by allowing an AF_RXRPC server to call
bind() twice on a socket to allow it to listen on two service IDs and then
call setsockopt() to instruct the server to upgrade one into the other if
the client requests it (by setting userStatus to 1 on the first DATA packet
on a connection). If the upgrade occurs, all further operations on that
connection are done with the new service ID. AF_RXRPC has to handle this
automatically as connections are not exposed to userspace.
Clients can request this facility by setting an RXRPC_UPGRADE_SERVICE
command in the sendmsg() control buffer and then observing the resultant
service ID in the msg_addr returned by recvmsg(). This should only be used
to probe the service. Clients should then use the returned service ID in
all subsequent communications with that server. Note that the kernel will
not retain this information should the connection expire from its cache.
The patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=rxrpc-rewrite
Tagged thusly:
git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git
rxrpc-rewrite-20170606
David
---
David Howells (4):
rxrpc: Separate the connection's protocol service ID from the lookup ID
rxrpc: Permit multiple service binding
rxrpc: Implement service upgrade
rxrpc: Add service upgrade support for client connections
Documentation/networking/rxrpc.txt | 68 +++++++++++++++++++++++++---
include/linux/rxrpc.h | 2 +
include/rxrpc/packet.h | 2 +
include/trace/events/rxrpc.h | 1
net/rxrpc/af_rxrpc.c | 88 ++++++++++++++++++++++++++----------
net/rxrpc/ar-internal.h | 17 ++++++-
net/rxrpc/call_accept.c | 5 +-
net/rxrpc/conn_client.c | 47 ++++++++++++++++---
net/rxrpc/conn_event.c | 4 +-
net/rxrpc/conn_object.c | 1
net/rxrpc/conn_service.c | 12 +++++
net/rxrpc/input.c | 17 +++++++
net/rxrpc/local_object.c | 1
net/rxrpc/output.c | 4 ++
net/rxrpc/proc.c | 2 -
net/rxrpc/recvmsg.c | 7 ++-
net/rxrpc/rxkad.c | 2 -
net/rxrpc/security.c | 5 +-
net/rxrpc/sendmsg.c | 19 ++++++--
19 files changed, 245 insertions(+), 59 deletions(-)
^ permalink raw reply
* [PATCH net-next 1/4] rxrpc: Separate the connection's protocol service ID from the lookup ID
From: David Howells @ 2017-06-06 9:54 UTC (permalink / raw)
To: netdev; +Cc: dhowells, linux-afs, linux-kernel
In-Reply-To: <149674286135.26138.12623162384868251541.stgit@warthog.procyon.org.uk>
Keep the rxrpc_connection struct's idea of the service ID that is exposed
in the protocol separate from the service ID that's used as a lookup key.
This allows the protocol service ID on a client connection to get upgraded
without making the connection unfindable for other client calls that also
would like to use the upgraded connection.
The connection's actual service ID is then returned through recvmsg() by
way of msg_name.
Whilst we're at it, we get rid of the last_service_id field from each
channel. The service ID is per-connection, not per-call and an entire
connection is upgraded in one go.
Signed-off-by: David Howells <dhowells@redhat.com>
---
net/rxrpc/af_rxrpc.c | 5 ++---
net/rxrpc/ar-internal.h | 2 +-
net/rxrpc/conn_client.c | 4 ++++
net/rxrpc/conn_event.c | 4 ++--
net/rxrpc/conn_object.c | 1 -
net/rxrpc/conn_service.c | 1 +
net/rxrpc/proc.c | 2 +-
net/rxrpc/recvmsg.c | 7 +++++--
net/rxrpc/rxkad.c | 2 +-
net/rxrpc/security.c | 4 ++--
10 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index cd34ffbff1d1..1e4ac889ec00 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -131,9 +131,8 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
{
struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)saddr;
- struct sock *sk = sock->sk;
struct rxrpc_local *local;
- struct rxrpc_sock *rx = rxrpc_sk(sk);
+ struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
u16 service_id = srx->srx_service;
int ret;
@@ -152,7 +151,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
memcpy(&rx->srx, srx, sizeof(rx->srx));
- local = rxrpc_lookup_local(sock_net(sock->sk), &rx->srx);
+ local = rxrpc_lookup_local(sock_net(&rx->sk), &rx->srx);
if (IS_ERR(local)) {
ret = PTR_ERR(local);
goto error_unlock;
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 067dbb3121d0..de98a49adb35 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -386,7 +386,6 @@ struct rxrpc_connection {
u32 call_counter; /* Call ID counter */
u32 last_call; /* ID of last call */
u8 last_type; /* Type of last packet */
- u16 last_service_id;
union {
u32 last_seq;
u32 last_abort;
@@ -417,6 +416,7 @@ struct rxrpc_connection {
atomic_t serial; /* packet serial number counter */
unsigned int hi_serial; /* highest serial number received */
u32 security_nonce; /* response re-use preventer */
+ u16 service_id; /* Service ID, possibly upgraded */
u8 size_align; /* data size alignment (for security) */
u8 security_size; /* security header size */
u8 security_ix; /* security type */
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index c86f3202f967..3f358bf424ad 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -188,6 +188,7 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp)
conn->params = *cp;
conn->out_clientflag = RXRPC_CLIENT_INITIATED;
conn->state = RXRPC_CONN_CLIENT;
+ conn->service_id = cp->service_id;
ret = rxrpc_get_client_connection_id(conn, gfp);
if (ret < 0)
@@ -343,6 +344,7 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
if (cp->exclusive) {
call->conn = candidate;
call->security_ix = candidate->security_ix;
+ call->service_id = candidate->service_id;
_leave(" = 0 [exclusive %d]", candidate->debug_id);
return 0;
}
@@ -392,6 +394,7 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
set_bit(RXRPC_CONN_IN_CLIENT_CONNS, &candidate->flags);
call->conn = candidate;
call->security_ix = candidate->security_ix;
+ call->service_id = candidate->service_id;
spin_unlock(&local->client_conns_lock);
_leave(" = 0 [new %d]", candidate->debug_id);
return 0;
@@ -413,6 +416,7 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
spin_lock(&conn->channel_lock);
call->conn = conn;
call->security_ix = conn->security_ix;
+ call->service_id = conn->service_id;
list_add(&call->chan_wait_link, &conn->waiting_calls);
spin_unlock(&conn->channel_lock);
_leave(" = 0 [extant %d]", conn->debug_id);
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index 46babcf82ce8..59a51a56e7c8 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -74,7 +74,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
pkt.whdr.userStatus = 0;
pkt.whdr.securityIndex = conn->security_ix;
pkt.whdr._rsvd = 0;
- pkt.whdr.serviceId = htons(chan->last_service_id);
+ pkt.whdr.serviceId = htons(conn->service_id);
len = sizeof(pkt.whdr);
switch (chan->last_type) {
@@ -208,7 +208,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
whdr.userStatus = 0;
whdr.securityIndex = conn->security_ix;
whdr._rsvd = 0;
- whdr.serviceId = htons(conn->params.service_id);
+ whdr.serviceId = htons(conn->service_id);
word = htonl(conn->local_abort);
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index ade4d3d0b2a7..5bb255107427 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -167,7 +167,6 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
* through the channel, whilst disposing of the actual call record.
*/
trace_rxrpc_disconnect_call(call);
- chan->last_service_id = call->service_id;
if (call->abort_code) {
chan->last_abort = call->abort_code;
chan->last_type = RXRPC_PACKET_TYPE_ABORT;
diff --git a/net/rxrpc/conn_service.c b/net/rxrpc/conn_service.c
index edfc633f7d5e..c7f8682a55b2 100644
--- a/net/rxrpc/conn_service.c
+++ b/net/rxrpc/conn_service.c
@@ -160,6 +160,7 @@ void rxrpc_new_incoming_connection(struct rxrpc_connection *conn,
conn->proto.epoch = sp->hdr.epoch;
conn->proto.cid = sp->hdr.cid & RXRPC_CIDMASK;
conn->params.service_id = sp->hdr.serviceId;
+ conn->service_id = sp->hdr.serviceId;
conn->security_ix = sp->hdr.securityIndex;
conn->out_clientflag = 0;
if (conn->security_ix)
diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
index e92d8405b15a..7421656963a9 100644
--- a/net/rxrpc/proc.c
+++ b/net/rxrpc/proc.c
@@ -190,7 +190,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
" %s %08x %08x %08x\n",
lbuff,
rbuff,
- conn->params.service_id,
+ conn->service_id,
conn->proto.cid,
rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
atomic_read(&conn->usage),
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index f9caf3b77509..bdece21f313d 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -522,8 +522,11 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
}
if (msg->msg_name) {
- size_t len = sizeof(call->conn->params.peer->srx);
- memcpy(msg->msg_name, &call->conn->params.peer->srx, len);
+ struct sockaddr_rxrpc *srx = msg->msg_name;
+ size_t len = sizeof(call->peer->srx);
+
+ memcpy(msg->msg_name, &call->peer->srx, len);
+ srx->srx_service = call->service_id;
msg->msg_namelen = len;
}
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index 29fe20ad04aa..46d1a1f0b55b 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -649,7 +649,7 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)
whdr.userStatus = 0;
whdr.securityIndex = conn->security_ix;
whdr._rsvd = 0;
- whdr.serviceId = htons(conn->params.service_id);
+ whdr.serviceId = htons(conn->service_id);
iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr);
diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c
index 7d921e56e715..b9f5dbbe0b8b 100644
--- a/net/rxrpc/security.c
+++ b/net/rxrpc/security.c
@@ -121,7 +121,7 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
_enter("");
- sprintf(kdesc, "%u:%u", conn->params.service_id, conn->security_ix);
+ sprintf(kdesc, "%u:%u", conn->service_id, conn->security_ix);
sec = rxrpc_security_lookup(conn->security_ix);
if (!sec) {
@@ -133,7 +133,7 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
read_lock(&local->services_lock);
rx = rcu_dereference_protected(local->service,
lockdep_is_held(&local->services_lock));
- if (rx && rx->srx.srx_service == conn->params.service_id)
+ if (rx && rx->srx.srx_service == conn->service_id)
goto found_service;
/* the service appears to have died */
^ permalink raw reply related
* [PATCH net-next 2/4] rxrpc: Permit multiple service binding
From: David Howells @ 2017-06-06 9:54 UTC (permalink / raw)
To: netdev; +Cc: dhowells, linux-afs, linux-kernel
In-Reply-To: <149674286135.26138.12623162384868251541.stgit@warthog.procyon.org.uk>
Permit bind() to be called on an AF_RXRPC socket more than once (currently
maximum twice) to bind multiple listening services to it. There are some
restrictions:
(1) All bind() calls involved must have a non-zero service ID.
(2) The service IDs must all be different.
(3) The rest of the address (notably the transport part) must be the same
in all (a single UDP socket is shared).
(4) This must be done before listen() or sendmsg() is called.
This allows someone to connect to the service socket with different service
IDs and lays the foundation for service upgrading.
The service ID used by an incoming call can be extracted from the msg_name
returned by recvmsg().
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/networking/rxrpc.txt | 4 ++
net/rxrpc/af_rxrpc.c | 62 +++++++++++++++++++++++-------------
net/rxrpc/ar-internal.h | 2 +
net/rxrpc/call_accept.c | 3 +-
net/rxrpc/local_object.c | 1 +
net/rxrpc/security.c | 3 +-
6 files changed, 51 insertions(+), 24 deletions(-)
diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt
index 1b63bbc6b94f..b7115ec55e04 100644
--- a/Documentation/networking/rxrpc.txt
+++ b/Documentation/networking/rxrpc.txt
@@ -600,6 +600,10 @@ A server would be set up to accept operations in the following manner:
};
bind(server, &srx, sizeof(srx));
+ More than one service ID may be bound to a socket, provided the transport
+ parameters are the same. The limit is currently two. To do this, bind()
+ should be called twice.
+
(3) The server is then set to listen out for incoming calls:
listen(server, 100);
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 1e4ac889ec00..3b982bca7d22 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -144,31 +144,48 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
lock_sock(&rx->sk);
- if (rx->sk.sk_state != RXRPC_UNBOUND) {
- ret = -EINVAL;
- goto error_unlock;
- }
-
- memcpy(&rx->srx, srx, sizeof(rx->srx));
+ switch (rx->sk.sk_state) {
+ case RXRPC_UNBOUND:
+ rx->srx = *srx;
+ local = rxrpc_lookup_local(sock_net(&rx->sk), &rx->srx);
+ if (IS_ERR(local)) {
+ ret = PTR_ERR(local);
+ goto error_unlock;
+ }
- local = rxrpc_lookup_local(sock_net(&rx->sk), &rx->srx);
- if (IS_ERR(local)) {
- ret = PTR_ERR(local);
- goto error_unlock;
- }
+ if (service_id) {
+ write_lock(&local->services_lock);
+ if (rcu_access_pointer(local->service))
+ goto service_in_use;
+ rx->local = local;
+ rcu_assign_pointer(local->service, rx);
+ write_unlock(&local->services_lock);
+
+ rx->sk.sk_state = RXRPC_SERVER_BOUND;
+ } else {
+ rx->local = local;
+ rx->sk.sk_state = RXRPC_CLIENT_BOUND;
+ }
+ break;
- if (service_id) {
- write_lock(&local->services_lock);
- if (rcu_access_pointer(local->service))
- goto service_in_use;
- rx->local = local;
- rcu_assign_pointer(local->service, rx);
- write_unlock(&local->services_lock);
+ case RXRPC_SERVER_BOUND:
+ ret = -EINVAL;
+ if (service_id == 0)
+ goto error_unlock;
+ ret = -EADDRINUSE;
+ if (service_id == rx->srx.srx_service)
+ goto error_unlock;
+ ret = -EINVAL;
+ srx->srx_service = rx->srx.srx_service;
+ if (memcmp(srx, &rx->srx, sizeof(*srx)) != 0)
+ goto error_unlock;
+ rx->second_service = service_id;
+ rx->sk.sk_state = RXRPC_SERVER_BOUND2;
+ break;
- rx->sk.sk_state = RXRPC_SERVER_BOUND;
- } else {
- rx->local = local;
- rx->sk.sk_state = RXRPC_CLIENT_BOUND;
+ default:
+ ret = -EINVAL;
+ goto error_unlock;
}
release_sock(&rx->sk);
@@ -205,6 +222,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
ret = -EADDRNOTAVAIL;
break;
case RXRPC_SERVER_BOUND:
+ case RXRPC_SERVER_BOUND2:
ASSERT(rx->local != NULL);
max = READ_ONCE(rxrpc_max_backlog);
ret = -EINVAL;
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index de98a49adb35..781fbc253b5a 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -61,6 +61,7 @@ enum {
RXRPC_CLIENT_UNBOUND, /* Unbound socket used as client */
RXRPC_CLIENT_BOUND, /* client local address bound */
RXRPC_SERVER_BOUND, /* server local address bound */
+ RXRPC_SERVER_BOUND2, /* second server local address bound */
RXRPC_SERVER_LISTENING, /* server listening for connections */
RXRPC_SERVER_LISTEN_DISABLED, /* server listening disabled */
RXRPC_CLOSE, /* socket is being closed */
@@ -142,6 +143,7 @@ struct rxrpc_sock {
u32 min_sec_level; /* minimum security level */
#define RXRPC_SECURITY_MAX RXRPC_SECURITY_ENCRYPT
bool exclusive; /* Exclusive connection for a client socket */
+ u16 second_service; /* Additional service bound to the endpoint */
sa_family_t family; /* Protocol family created with */
struct sockaddr_rxrpc srx; /* local address */
struct sockaddr_rxrpc connect_srx; /* Default client address from connect() */
diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
index a8515b0d4717..544df53ccf79 100644
--- a/net/rxrpc/call_accept.c
+++ b/net/rxrpc/call_accept.c
@@ -341,7 +341,8 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
/* Get the socket providing the service */
rx = rcu_dereference(local->service);
- if (rx && service_id == rx->srx.srx_service)
+ if (rx && (service_id == rx->srx.srx_service ||
+ service_id == rx->second_service))
goto found_service;
trace_rxrpc_abort("INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c
index 17d79fd73ade..38b99db30e54 100644
--- a/net/rxrpc/local_object.c
+++ b/net/rxrpc/local_object.c
@@ -94,6 +94,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
rwlock_init(&local->services_lock);
local->debug_id = atomic_inc_return(&rxrpc_debug_id);
memcpy(&local->srx, srx, sizeof(*srx));
+ local->srx.srx_service = 0;
}
_leave(" = %p", local);
diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c
index b9f5dbbe0b8b..e9f428351293 100644
--- a/net/rxrpc/security.c
+++ b/net/rxrpc/security.c
@@ -133,7 +133,8 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
read_lock(&local->services_lock);
rx = rcu_dereference_protected(local->service,
lockdep_is_held(&local->services_lock));
- if (rx && rx->srx.srx_service == conn->service_id)
+ if (rx && (rx->srx.srx_service == conn->service_id ||
+ rx->second_service == conn->service_id))
goto found_service;
/* the service appears to have died */
^ permalink raw reply related
* [PATCH net-next 3/4] rxrpc: Implement service upgrade
From: David Howells @ 2017-06-06 9:54 UTC (permalink / raw)
To: netdev; +Cc: dhowells, linux-afs, linux-kernel
In-Reply-To: <149674286135.26138.12623162384868251541.stgit@warthog.procyon.org.uk>
Implement AuriStor's service upgrade facility. There are three problems
that this is meant to deal with:
(1) Various of the standard AFS RPC calls have IPv4 addresses in their
requests and/or replies - but there's no room for including IPv6
addresses.
(2) Definition of IPv6-specific RPC operations in the standard operation
sets has not yet been achieved.
(3) One could envision the creation a new service on the same port that as
the original service. The new service could implement improved
operations - and the client could try this first, falling back to the
original service if it's not there.
Unfortunately, certain servers ignore packets addressed to a service
they don't implement and don't respond in any way - not even with an
ABORT. This means that the client must then wait for the call timeout
to occur.
What service upgrade does is to see if the connection is marked as being
'upgradeable' and if so, change the service ID in the server and thus the
request and reply formats. Note that the upgrade isn't mandatory - a
server that supports only the original call set will ignore the upgrade
request.
In the protocol, the procedure is then as follows:
(1) To request an upgrade, the first DATA packet in a new connection must
have the userStatus set to 1 (this is normally 0). The userStatus
value is normally ignored by the server.
(2) If the server doesn't support upgrading, the reply packets will
contain the same service ID as for the first request packet.
(3) If the server does support upgrading, all future reply packets on that
connection will contain the new service ID and the new service ID will
be applied to *all* further calls on that connection as well.
(4) The RPC op used to probe the upgrade must take the same request data
as the shadow call in the upgrade set (but may return a different
reply). GetCapability RPC ops were added to all standard sets for
just this purpose. Ops where the request formats differ cannot be
used for probing.
(5) The client must wait for completion of the probe before sending any
further RPC ops to the same destination. It should then use the
service ID that recvmsg() reported back in all future calls.
(6) The shadow service must have call definitions for all the operation
IDs defined by the original service.
To support service upgrading, a server should:
(1) Call bind() twice on its AF_RXRPC socket before calling listen().
Each bind() should supply a different service ID, but the transport
addresses must be the same. This allows the server to receive
requests with either service ID.
(2) Enable automatic upgrading by calling setsockopt(), specifying
RXRPC_UPGRADEABLE_SERVICE and passing in a two-member array of
unsigned shorts as the argument:
unsigned short optval[2];
This specifies a pair of service IDs. They must be different and must
match the service IDs bound to the socket. Member 0 is the service ID
to upgrade from and member 1 is the service ID to upgrade to.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/networking/rxrpc.txt | 34 ++++++++++++++++++++++++++--------
include/linux/rxrpc.h | 1 +
include/rxrpc/packet.h | 2 ++
net/rxrpc/af_rxrpc.c | 23 +++++++++++++++++++++++
net/rxrpc/ar-internal.h | 10 ++++++++--
net/rxrpc/call_accept.c | 2 +-
net/rxrpc/conn_service.c | 11 ++++++++++-
7 files changed, 71 insertions(+), 12 deletions(-)
diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt
index b7115ec55e04..2a1662760450 100644
--- a/Documentation/networking/rxrpc.txt
+++ b/Documentation/networking/rxrpc.txt
@@ -433,6 +433,13 @@ AF_RXRPC sockets support a few socket options at the SOL_RXRPC level:
Encrypted checksum plus entire packet padded and encrypted, including
actual packet length.
+ (*) RXRPC_UPGRADEABLE_SERVICE
+
+ This is used to indicate that a service socket with two bindings may
+ upgrade one bound service to the other if requested by the client. optval
+ must point to an array of two unsigned short ints. The first is the
+ service ID to upgrade from and the second the service ID to upgrade to.
+
========
SECURITY
@@ -588,7 +595,7 @@ A server would be set up to accept operations in the following manner:
The keyring can be manipulated after it has been given to the socket. This
permits the server to add more keys, replace keys, etc. whilst it is live.
- (2) A local address must then be bound:
+ (3) A local address must then be bound:
struct sockaddr_rxrpc srx = {
.srx_family = AF_RXRPC,
@@ -604,11 +611,22 @@ A server would be set up to accept operations in the following manner:
parameters are the same. The limit is currently two. To do this, bind()
should be called twice.
- (3) The server is then set to listen out for incoming calls:
+ (4) If service upgrading is required, first two service IDs must have been
+ bound and then the following option must be set:
+
+ unsigned short service_ids[2] = { from_ID, to_ID };
+ setsockopt(server, SOL_RXRPC, RXRPC_UPGRADEABLE_SERVICE,
+ service_ids, sizeof(service_ids));
+
+ This will automatically upgrade connections on service from_ID to service
+ to_ID if they request it. This will be reflected in msg_name obtained
+ through recvmsg() when the request data is delivered to userspace.
+
+ (5) The server is then set to listen out for incoming calls:
listen(server, 100);
- (4) The kernel notifies the server of pending incoming connections by sending
+ (6) The kernel notifies the server of pending incoming connections by sending
it a message for each. This is received with recvmsg() on the server
socket. It has no data, and has a single dataless control message
attached:
@@ -620,13 +638,13 @@ A server would be set up to accept operations in the following manner:
the time it is accepted - in which case the first call still on the queue
will be accepted.
- (5) The server then accepts the new call by issuing a sendmsg() with two
+ (7) The server then accepts the new call by issuing a sendmsg() with two
pieces of control data and no actual data:
RXRPC_ACCEPT - indicate connection acceptance
RXRPC_USER_CALL_ID - specify user ID for this call
- (6) The first request data packet will then be posted to the server socket for
+ (8) The first request data packet will then be posted to the server socket for
recvmsg() to pick up. At that point, the RxRPC address for the call can
be read from the address fields in the msghdr struct.
@@ -638,7 +656,7 @@ A server would be set up to accept operations in the following manner:
RXRPC_USER_CALL_ID - specifies the user ID for this call
- (8) The reply data should then be posted to the server socket using a series
+ (9) The reply data should then be posted to the server socket using a series
of sendmsg() calls, each with the following control messages attached:
RXRPC_USER_CALL_ID - specifies the user ID for this call
@@ -646,7 +664,7 @@ A server would be set up to accept operations in the following manner:
MSG_MORE should be set in msghdr::msg_flags on all but the last message
for a particular call.
- (9) The final ACK from the client will be posted for retrieval by recvmsg()
+(10) The final ACK from the client will be posted for retrieval by recvmsg()
when it is received. It will take the form of a dataless message with two
control messages attached:
@@ -656,7 +674,7 @@ A server would be set up to accept operations in the following manner:
MSG_EOR will be flagged to indicate that this is the final message for
this call.
-(10) Up to the point the final packet of reply data is sent, the call can be
+(11) Up to the point the final packet of reply data is sent, the call can be
aborted by calling sendmsg() with a dataless message with the following
control messages attached:
diff --git a/include/linux/rxrpc.h b/include/linux/rxrpc.h
index c68307bc306f..634116561a6a 100644
--- a/include/linux/rxrpc.h
+++ b/include/linux/rxrpc.h
@@ -37,6 +37,7 @@ struct sockaddr_rxrpc {
#define RXRPC_SECURITY_KEYRING 2 /* [srvr] set ring of server security keys */
#define RXRPC_EXCLUSIVE_CONNECTION 3 /* Deprecated; use RXRPC_EXCLUSIVE_CALL instead */
#define RXRPC_MIN_SECURITY_LEVEL 4 /* minimum security level */
+#define RXRPC_UPGRADEABLE_SERVICE 5 /* Upgrade service[0] -> service[1] */
/*
* RxRPC control messages
diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h
index 703a64b4681a..a2dcfb850b9f 100644
--- a/include/rxrpc/packet.h
+++ b/include/rxrpc/packet.h
@@ -58,6 +58,8 @@ struct rxrpc_wire_header {
#define RXRPC_SLOW_START_OK 0x20 /* [ACK] slow start supported */
uint8_t userStatus; /* app-layer defined status */
+#define RXRPC_USERSTATUS_SERVICE_UPGRADE 0x01 /* AuriStor service upgrade request */
+
uint8_t securityIndex; /* security protocol ID */
union {
__be16 _rsvd; /* reserved */
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 3b982bca7d22..0c4dc4a7832c 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -490,6 +490,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
{
struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
unsigned int min_sec_level;
+ u16 service_upgrade[2];
int ret;
_enter(",%d,%d,,%d", level, optname, optlen);
@@ -546,6 +547,28 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
rx->min_sec_level = min_sec_level;
goto success;
+ case RXRPC_UPGRADEABLE_SERVICE:
+ ret = -EINVAL;
+ if (optlen != sizeof(service_upgrade) ||
+ rx->service_upgrade.from != 0)
+ goto error;
+ ret = -EISCONN;
+ if (rx->sk.sk_state != RXRPC_SERVER_BOUND2)
+ goto error;
+ ret = -EFAULT;
+ if (copy_from_user(service_upgrade, optval,
+ sizeof(service_upgrade)) != 0)
+ goto error;
+ ret = -EINVAL;
+ if ((service_upgrade[0] != rx->srx.srx_service ||
+ service_upgrade[1] != rx->second_service) &&
+ (service_upgrade[0] != rx->second_service ||
+ service_upgrade[1] != rx->srx.srx_service))
+ goto error;
+ rx->service_upgrade.from = service_upgrade[0];
+ rx->service_upgrade.to = service_upgrade[1];
+ goto success;
+
default:
break;
}
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 781fbc253b5a..c1ebd886a53f 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -144,8 +144,13 @@ struct rxrpc_sock {
#define RXRPC_SECURITY_MAX RXRPC_SECURITY_ENCRYPT
bool exclusive; /* Exclusive connection for a client socket */
u16 second_service; /* Additional service bound to the endpoint */
+ struct {
+ /* Service upgrade information */
+ u16 from; /* Service ID to upgrade (if not 0) */
+ u16 to; /* service ID to upgrade to */
+ } service_upgrade;
sa_family_t family; /* Protocol family created with */
- struct sockaddr_rxrpc srx; /* local address */
+ struct sockaddr_rxrpc srx; /* Primary Service/local addresses */
struct sockaddr_rxrpc connect_srx; /* Default client address from connect() */
};
@@ -861,7 +866,8 @@ static inline void rxrpc_put_connection(struct rxrpc_connection *conn)
struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *,
struct sk_buff *);
struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *, gfp_t);
-void rxrpc_new_incoming_connection(struct rxrpc_connection *, struct sk_buff *);
+void rxrpc_new_incoming_connection(struct rxrpc_sock *,
+ struct rxrpc_connection *, struct sk_buff *);
void rxrpc_unpublish_service_conn(struct rxrpc_connection *);
/*
diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
index 544df53ccf79..0d4d84e8c074 100644
--- a/net/rxrpc/call_accept.c
+++ b/net/rxrpc/call_accept.c
@@ -296,7 +296,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
conn->params.local = local;
conn->params.peer = peer;
rxrpc_see_connection(conn);
- rxrpc_new_incoming_connection(conn, skb);
+ rxrpc_new_incoming_connection(rx, conn, skb);
} else {
rxrpc_get_connection(conn);
}
diff --git a/net/rxrpc/conn_service.c b/net/rxrpc/conn_service.c
index c7f8682a55b2..e60fcd2a4a02 100644
--- a/net/rxrpc/conn_service.c
+++ b/net/rxrpc/conn_service.c
@@ -150,7 +150,8 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn
* Set up an incoming connection. This is called in BH context with the RCU
* read lock held.
*/
-void rxrpc_new_incoming_connection(struct rxrpc_connection *conn,
+void rxrpc_new_incoming_connection(struct rxrpc_sock *rx,
+ struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
@@ -168,6 +169,14 @@ void rxrpc_new_incoming_connection(struct rxrpc_connection *conn,
else
conn->state = RXRPC_CONN_SERVICE;
+ /* See if we should upgrade the service. This can only happen on the
+ * first packet on a new connection. Once done, it applies to all
+ * subsequent calls on that connection.
+ */
+ if (sp->hdr.userStatus == RXRPC_USERSTATUS_SERVICE_UPGRADE &&
+ conn->service_id == rx->service_upgrade.from)
+ conn->service_id = rx->service_upgrade.to;
+
/* Make the connection a target for incoming packets. */
rxrpc_publish_service_conn(conn->params.peer, conn);
^ permalink raw reply related
* [PATCH net-next 4/4] rxrpc: Add service upgrade support for client connections
From: David Howells @ 2017-06-06 9:54 UTC (permalink / raw)
To: netdev; +Cc: dhowells, linux-afs, linux-kernel
In-Reply-To: <149674286135.26138.12623162384868251541.stgit@warthog.procyon.org.uk>
Make it possible for a client to use AuriStor's service upgrade facility.
The client does this by adding an RXRPC_UPGRADE_SERVICE control message to
the first sendmsg() of a call. This takes no parameters.
When recvmsg() starts returning data from the call, the service ID field in
the returned msg_name will reflect the result of the upgrade attempt. If
the upgrade was ignored, srx_service will match what was set in the
sendmsg(); if the upgrade happened the srx_service will be altered to
indicate the service the server upgraded to.
Note that:
(1) The choice of upgrade service is up to the server
(2) Further client calls to the same server that would share a connection
are blocked if an upgrade probe is in progress.
(3) This should only be used to probe the service. Clients should then
use the returned service ID in all subsequent communications with that
server (and not set the upgrade). Note that the kernel will not
retain this information should the connection expire from its cache.
(4) If a server that supports upgrading is replaced by one that doesn't,
whilst a connection is live, and if the replacement is running, say,
OpenAFS 1.6.4 or older or an older IBM AFS, then the replacement
server will not respond to packets sent to the upgraded connection.
At this point, calls will time out and the server must be reprobed.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/networking/rxrpc.txt | 30 +++++++++++++++++++++++++
include/linux/rxrpc.h | 1 +
include/trace/events/rxrpc.h | 1 +
net/rxrpc/ar-internal.h | 3 +++
net/rxrpc/conn_client.c | 43 +++++++++++++++++++++++++++++-------
net/rxrpc/input.c | 17 ++++++++++++++
net/rxrpc/output.c | 4 +++
net/rxrpc/sendmsg.c | 19 +++++++++++++---
8 files changed, 106 insertions(+), 12 deletions(-)
diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt
index 2a1662760450..18078e630a63 100644
--- a/Documentation/networking/rxrpc.txt
+++ b/Documentation/networking/rxrpc.txt
@@ -325,6 +325,8 @@ calls, to invoke certain actions and to report certain conditions. These are:
RXRPC_LOCAL_ERROR -rt error num Local error encountered
RXRPC_NEW_CALL -r- n/a New call received
RXRPC_ACCEPT s-- n/a Accept new call
+ RXRPC_EXCLUSIVE_CALL s-- n/a Make an exclusive client call
+ RXRPC_UPGRADE_SERVICE s-- n/a Client call can be upgraded
(SRT = usable in Sendmsg / delivered by Recvmsg / Terminal message)
@@ -387,6 +389,23 @@ calls, to invoke certain actions and to report certain conditions. These are:
return error ENODATA. If the user ID is already in use by another call,
then error EBADSLT will be returned.
+ (*) RXRPC_EXCLUSIVE_CALL
+
+ This is used to indicate that a client call should be made on a one-off
+ connection. The connection is discarded once the call has terminated.
+
+ (*) RXRPC_UPGRADE_SERVICE
+
+ This is used to make a client call to probe if the specified service ID
+ may be upgraded by the server. The caller must check msg_name returned to
+ recvmsg() for the service ID actually in use. The operation probed must
+ be one that takes the same arguments in both services.
+
+ Once this has been used to establish the upgrade capability (or lack
+ thereof) of the server, the service ID returned should be used for all
+ future communication to that server and RXRPC_UPGRADE_SERVICE should no
+ longer be set.
+
==============
SOCKET OPTIONS
@@ -566,6 +585,17 @@ A client would issue an operation by:
buffer instead, and MSG_EOR will be flagged to indicate the end of that
call.
+A client may ask for a service ID it knows and ask that this be upgraded to a
+better service if one is available by supplying RXRPC_UPGRADE_SERVICE on the
+first sendmsg() of a call. The client should then check srx_service in the
+msg_name filled in by recvmsg() when collecting the result. srx_service will
+hold the same value as given to sendmsg() if the upgrade request was ignored by
+the service - otherwise it will be altered to indicate the service ID the
+server upgraded to. Note that the upgraded service ID is chosen by the server.
+The caller has to wait until it sees the service ID in the reply before sending
+any more calls (further calls to the same destination will be blocked until the
+probe is concluded).
+
====================
EXAMPLE SERVER USAGE
diff --git a/include/linux/rxrpc.h b/include/linux/rxrpc.h
index 634116561a6a..707910c6c6c5 100644
--- a/include/linux/rxrpc.h
+++ b/include/linux/rxrpc.h
@@ -54,6 +54,7 @@ struct sockaddr_rxrpc {
#define RXRPC_NEW_CALL 8 /* -r: [Service] new incoming call notification */
#define RXRPC_ACCEPT 9 /* s-: [Service] accept request */
#define RXRPC_EXCLUSIVE_CALL 10 /* s-: Call should be on exclusive connection */
+#define RXRPC_UPGRADE_SERVICE 11 /* s-: Request service upgrade for client call */
/*
* RxRPC security levels
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 29a3d53a4015..ebe96796027a 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -233,6 +233,7 @@ enum rxrpc_congest_change {
EM(RXRPC_CONN_CLIENT_INACTIVE, "Inac") \
EM(RXRPC_CONN_CLIENT_WAITING, "Wait") \
EM(RXRPC_CONN_CLIENT_ACTIVE, "Actv") \
+ EM(RXRPC_CONN_CLIENT_UPGRADE, "Upgd") \
EM(RXRPC_CONN_CLIENT_CULLED, "Cull") \
E_(RXRPC_CONN_CLIENT_IDLE, "Idle") \
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index c1ebd886a53f..e9b536cb0acf 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -320,6 +320,7 @@ struct rxrpc_conn_parameters {
struct rxrpc_peer *peer; /* Remote endpoint */
struct key *key; /* Security details */
bool exclusive; /* T if conn is exclusive */
+ bool upgrade; /* T if service ID can be upgraded */
u16 service_id; /* Service ID for this connection */
u32 security_level; /* Security level selected */
};
@@ -334,6 +335,7 @@ enum rxrpc_conn_flag {
RXRPC_CONN_EXPOSED, /* Conn has extra ref for exposure */
RXRPC_CONN_DONT_REUSE, /* Don't reuse this connection */
RXRPC_CONN_COUNTED, /* Counted by rxrpc_nr_client_conns */
+ RXRPC_CONN_PROBING_FOR_UPGRADE, /* Probing for service upgrade */
};
/*
@@ -350,6 +352,7 @@ enum rxrpc_conn_cache_state {
RXRPC_CONN_CLIENT_INACTIVE, /* Conn is not yet listed */
RXRPC_CONN_CLIENT_WAITING, /* Conn is on wait list, waiting for capacity */
RXRPC_CONN_CLIENT_ACTIVE, /* Conn is on active list, doing calls */
+ RXRPC_CONN_CLIENT_UPGRADE, /* Conn is on active list, probing for upgrade */
RXRPC_CONN_CLIENT_CULLED, /* Conn is culled and delisted, doing calls */
RXRPC_CONN_CLIENT_IDLE, /* Conn is on idle list, doing mostly nothing */
RXRPC_CONN__NR_CACHE_STATES
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index 3f358bf424ad..dd8bb919c15a 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -36,12 +36,15 @@
*
* rxrpc_nr_active_client_conns is held incremented also.
*
- * (4) CULLED - The connection got summarily culled to try and free up
+ * (4) UPGRADE - As for ACTIVE, but only one call may be in progress and is
+ * being used to probe for service upgrade.
+ *
+ * (5) CULLED - The connection got summarily culled to try and free up
* capacity. Calls currently in progress on the connection are allowed to
* continue, but new calls will have to wait. There can be no waiters in
* this state - the conn would have to go to the WAITING state instead.
*
- * (5) IDLE - The connection has no calls in progress upon it and must have
+ * (6) IDLE - The connection has no calls in progress upon it and must have
* been exposed to the world (ie. the EXPOSED flag must be set). When it
* expires, the EXPOSED flag is cleared and the connection transitions to
* the INACTIVE state.
@@ -184,6 +187,8 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp)
atomic_set(&conn->usage, 1);
if (cp->exclusive)
__set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
+ if (cp->upgrade)
+ __set_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags);
conn->params = *cp;
conn->out_clientflag = RXRPC_CLIENT_INITIATED;
@@ -300,7 +305,8 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
#define cmp(X) ((long)conn->params.X - (long)cp->X)
diff = (cmp(peer) ?:
cmp(key) ?:
- cmp(security_level));
+ cmp(security_level) ?:
+ cmp(upgrade));
#undef cmp
if (diff < 0) {
p = p->rb_left;
@@ -365,7 +371,8 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
#define cmp(X) ((long)conn->params.X - (long)candidate->params.X)
diff = (cmp(peer) ?:
cmp(key) ?:
- cmp(security_level));
+ cmp(security_level) ?:
+ cmp(upgrade));
#undef cmp
if (diff < 0) {
pp = &(*pp)->rb_left;
@@ -436,8 +443,13 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
static void rxrpc_activate_conn(struct rxrpc_net *rxnet,
struct rxrpc_connection *conn)
{
- trace_rxrpc_client(conn, -1, rxrpc_client_to_active);
- conn->cache_state = RXRPC_CONN_CLIENT_ACTIVE;
+ if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags)) {
+ trace_rxrpc_client(conn, -1, rxrpc_client_to_upgrade);
+ conn->cache_state = RXRPC_CONN_CLIENT_UPGRADE;
+ } else {
+ trace_rxrpc_client(conn, -1, rxrpc_client_to_active);
+ conn->cache_state = RXRPC_CONN_CLIENT_ACTIVE;
+ }
rxnet->nr_active_client_conns++;
list_move_tail(&conn->cache_link, &rxnet->active_client_conns);
}
@@ -461,7 +473,8 @@ static void rxrpc_animate_client_conn(struct rxrpc_net *rxnet,
_enter("%d,%d", conn->debug_id, conn->cache_state);
- if (conn->cache_state == RXRPC_CONN_CLIENT_ACTIVE)
+ if (conn->cache_state == RXRPC_CONN_CLIENT_ACTIVE ||
+ conn->cache_state == RXRPC_CONN_CLIENT_UPGRADE)
goto out;
spin_lock(&rxnet->client_conn_cache_lock);
@@ -474,6 +487,7 @@ static void rxrpc_animate_client_conn(struct rxrpc_net *rxnet,
switch (conn->cache_state) {
case RXRPC_CONN_CLIENT_ACTIVE:
+ case RXRPC_CONN_CLIENT_UPGRADE:
case RXRPC_CONN_CLIENT_WAITING:
break;
@@ -577,6 +591,9 @@ static void rxrpc_activate_channels_locked(struct rxrpc_connection *conn)
case RXRPC_CONN_CLIENT_ACTIVE:
mask = RXRPC_ACTIVE_CHANS_MASK;
break;
+ case RXRPC_CONN_CLIENT_UPGRADE:
+ mask = 0x01;
+ break;
default:
return;
}
@@ -787,6 +804,15 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
spin_lock(&rxnet->client_conn_cache_lock);
switch (conn->cache_state) {
+ case RXRPC_CONN_CLIENT_UPGRADE:
+ /* Deal with termination of a service upgrade probe. */
+ if (test_bit(RXRPC_CONN_EXPOSED, &conn->flags)) {
+ clear_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags);
+ trace_rxrpc_client(conn, channel, rxrpc_client_to_active);
+ conn->cache_state = RXRPC_CONN_CLIENT_ACTIVE;
+ rxrpc_activate_channels_locked(conn);
+ }
+ /* fall through */
case RXRPC_CONN_CLIENT_ACTIVE:
if (list_empty(&conn->waiting_calls)) {
rxrpc_deactivate_one_channel(conn, channel);
@@ -941,7 +967,8 @@ static void rxrpc_cull_active_client_conns(struct rxrpc_net *rxnet)
ASSERT(!list_empty(&rxnet->active_client_conns));
conn = list_entry(rxnet->active_client_conns.next,
struct rxrpc_connection, cache_link);
- ASSERTCMP(conn->cache_state, ==, RXRPC_CONN_CLIENT_ACTIVE);
+ ASSERTIFCMP(conn->cache_state != RXRPC_CONN_CLIENT_ACTIVE,
+ conn->cache_state, ==, RXRPC_CONN_CLIENT_UPGRADE);
if (list_empty(&conn->waiting_calls)) {
trace_rxrpc_client(conn, -1, rxrpc_client_to_culled);
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
index 45dba732a3b4..e56e23ed2229 100644
--- a/net/rxrpc/input.c
+++ b/net/rxrpc/input.c
@@ -1142,6 +1142,13 @@ void rxrpc_data_ready(struct sock *udp_sk)
if (sp->hdr.securityIndex != conn->security_ix)
goto wrong_security;
+ if (sp->hdr.serviceId != conn->service_id) {
+ if (!test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) ||
+ conn->service_id != conn->params.service_id)
+ goto reupgrade;
+ conn->service_id = sp->hdr.serviceId;
+ }
+
if (sp->hdr.callNumber == 0) {
/* Connection-level packet */
_debug("CONN %p {%d}", conn, conn->debug_id);
@@ -1194,6 +1201,9 @@ void rxrpc_data_ready(struct sock *udp_sk)
rxrpc_input_implicit_end_call(conn, call);
call = NULL;
}
+
+ if (call && sp->hdr.serviceId != call->service_id)
+ call->service_id = sp->hdr.serviceId;
} else {
skew = 0;
call = NULL;
@@ -1237,11 +1247,18 @@ void rxrpc_data_ready(struct sock *udp_sk)
skb->priority = RXKADINCONSISTENCY;
goto post_abort;
+reupgrade:
+ rcu_read_unlock();
+ trace_rxrpc_abort("UPG", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
+ RX_PROTOCOL_ERROR, EBADMSG);
+ goto protocol_error;
+
bad_message_unlock:
rcu_read_unlock();
bad_message:
trace_rxrpc_abort("BAD", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
RX_PROTOCOL_ERROR, EBADMSG);
+protocol_error:
skb->priority = RX_PROTOCOL_ERROR;
post_abort:
skb->mark = RXRPC_SKB_MARK_LOCAL_ABORT;
diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
index 5dab1ff3a6c2..5bd2d0fa4a03 100644
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -292,6 +292,10 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
whdr._rsvd = htons(sp->hdr._rsvd);
whdr.serviceId = htons(call->service_id);
+ if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) &&
+ sp->hdr.seq == 1)
+ whdr.userStatus = RXRPC_USERSTATUS_SERVICE_UPGRADE;
+
iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr);
iov[1].iov_base = skb->head;
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 96ffa5d5733b..5a4801e7f560 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -366,7 +366,8 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg,
unsigned long *user_call_ID,
enum rxrpc_command *command,
u32 *abort_code,
- bool *_exclusive)
+ bool *_exclusive,
+ bool *_upgrade)
{
struct cmsghdr *cmsg;
bool got_user_ID = false;
@@ -429,6 +430,13 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg,
if (len != 0)
return -EINVAL;
break;
+
+ case RXRPC_UPGRADE_SERVICE:
+ *_upgrade = true;
+ if (len != 0)
+ return -EINVAL;
+ break;
+
default:
return -EINVAL;
}
@@ -447,7 +455,8 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg,
*/
static struct rxrpc_call *
rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
- unsigned long user_call_ID, bool exclusive)
+ unsigned long user_call_ID, bool exclusive,
+ bool upgrade)
__releases(&rx->sk.sk_lock.slock)
{
struct rxrpc_conn_parameters cp;
@@ -472,6 +481,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
cp.key = rx->key;
cp.security_level = rx->min_sec_level;
cp.exclusive = rx->exclusive | exclusive;
+ cp.upgrade = upgrade;
cp.service_id = srx->srx_service;
call = rxrpc_new_client_call(rx, &cp, srx, user_call_ID, GFP_KERNEL);
/* The socket is now unlocked */
@@ -493,13 +503,14 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
struct rxrpc_call *call;
unsigned long user_call_ID = 0;
bool exclusive = false;
+ bool upgrade = true;
u32 abort_code = 0;
int ret;
_enter("");
ret = rxrpc_sendmsg_cmsg(msg, &user_call_ID, &cmd, &abort_code,
- &exclusive);
+ &exclusive, &upgrade);
if (ret < 0)
goto error_release_sock;
@@ -521,7 +532,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
if (cmd != RXRPC_CMD_SEND_DATA)
goto error_release_sock;
call = rxrpc_new_client_call_for_sendmsg(rx, msg, user_call_ID,
- exclusive);
+ exclusive, upgrade);
/* The socket is now unlocked... */
if (IS_ERR(call))
return PTR_ERR(call);
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox