mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-24 19:40:21 +09:00
Merge tag 'v4.4.71' into linux-linaro-lsk-v4.4
This is the 4.4.71 stable release
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 70
|
||||
SUBLEVEL = 71
|
||||
EXTRAVERSION =
|
||||
NAME = Blurry Fish Butt
|
||||
|
||||
|
||||
@@ -91,9 +91,9 @@ extern unsigned long pfn_base;
|
||||
* ZERO_PAGE is a global shared page that is always zero: used
|
||||
* for zero-mapped memory areas etc..
|
||||
*/
|
||||
extern unsigned long empty_zero_page;
|
||||
extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
|
||||
|
||||
#define ZERO_PAGE(vaddr) (virt_to_page(&empty_zero_page))
|
||||
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
|
||||
|
||||
/*
|
||||
* In general all page table modifications should use the V8 atomic
|
||||
|
||||
@@ -16,7 +16,7 @@ extern char reboot_command[];
|
||||
*/
|
||||
extern unsigned char boot_cpu_id;
|
||||
|
||||
extern unsigned long empty_zero_page;
|
||||
extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
|
||||
|
||||
extern int serial_console;
|
||||
static inline int con_is_present(void)
|
||||
|
||||
@@ -301,7 +301,7 @@ void __init mem_init(void)
|
||||
|
||||
|
||||
/* Saves us work later. */
|
||||
memset((void *)&empty_zero_page, 0, PAGE_SIZE);
|
||||
memset((void *)empty_zero_page, 0, PAGE_SIZE);
|
||||
|
||||
i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5);
|
||||
i += 1;
|
||||
|
||||
@@ -374,7 +374,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
|
||||
|
||||
rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);
|
||||
if (rc <= 0) {
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
|
||||
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
|
||||
if (rc == -ERESTARTSYS)
|
||||
return rc;
|
||||
@@ -387,7 +387,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
|
||||
for (i = 0; i < bytes_to_write; i++) {
|
||||
rc = wait_for_bulk_out_ready(dev);
|
||||
if (rc <= 0) {
|
||||
DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n",
|
||||
DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2zx\n",
|
||||
rc);
|
||||
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
|
||||
if (rc == -ERESTARTSYS)
|
||||
@@ -403,7 +403,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
|
||||
rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);
|
||||
|
||||
if (rc <= 0) {
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
|
||||
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
|
||||
if (rc == -ERESTARTSYS)
|
||||
return rc;
|
||||
|
||||
@@ -783,20 +783,23 @@ void psb_intel_lvds_init(struct drm_device *dev,
|
||||
if (scan->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
mode_dev->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, scan);
|
||||
DRM_DEBUG_KMS("Using mode from DDC\n");
|
||||
goto out; /* FIXME: check for quirks */
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed to get EDID, what about VBT? do we need this? */
|
||||
if (mode_dev->vbt_mode)
|
||||
if (dev_priv->lfp_lvds_vbt_mode) {
|
||||
mode_dev->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, mode_dev->vbt_mode);
|
||||
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
||||
|
||||
if (!mode_dev->panel_fixed_mode)
|
||||
if (dev_priv->lfp_lvds_vbt_mode)
|
||||
mode_dev->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev,
|
||||
dev_priv->lfp_lvds_vbt_mode);
|
||||
if (mode_dev->panel_fixed_mode) {
|
||||
mode_dev->panel_fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
DRM_DEBUG_KMS("Using mode from VBT\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't get EDID, try checking if the panel is already turned
|
||||
@@ -813,6 +816,7 @@ void psb_intel_lvds_init(struct drm_device *dev,
|
||||
if (mode_dev->panel_fixed_mode) {
|
||||
mode_dev->panel_fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
DRM_DEBUG_KMS("Using pre-programmed mode\n");
|
||||
goto out; /* FIXME: check for quirks */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,6 +776,12 @@ bool ci_dpm_vblank_too_short(struct radeon_device *rdev)
|
||||
u32 vblank_time = r600_dpm_get_vblank_time(rdev);
|
||||
u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
|
||||
|
||||
/* disable mclk switching if the refresh is >120Hz, even if the
|
||||
* blanking period would allow it
|
||||
*/
|
||||
if (r600_dpm_get_vrefresh(rdev) > 120)
|
||||
return true;
|
||||
|
||||
if (vblank_time < switch_limit)
|
||||
return true;
|
||||
else
|
||||
|
||||
@@ -7762,7 +7762,7 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
|
||||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
@@ -7792,7 +7792,7 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
|
||||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_RX_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
||||
@@ -4924,7 +4924,7 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
|
||||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
@@ -4955,7 +4955,7 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
|
||||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_RX_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
||||
@@ -3945,7 +3945,7 @@ static void r600_irq_ack(struct radeon_device *rdev)
|
||||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
||||
@@ -6335,7 +6335,7 @@ static inline void si_irq_ack(struct radeon_device *rdev)
|
||||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
@@ -6366,7 +6366,7 @@ static inline void si_irq_ack(struct radeon_device *rdev)
|
||||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_RX_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
||||
@@ -1440,37 +1440,38 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
|
||||
{
|
||||
unsigned char *data = wacom->data;
|
||||
|
||||
if (wacom->pen_input)
|
||||
if (wacom->pen_input) {
|
||||
dev_dbg(wacom->pen_input->dev.parent,
|
||||
"%s: received report #%d\n", __func__, data[0]);
|
||||
else if (wacom->touch_input)
|
||||
|
||||
if (len == WACOM_PKGLEN_PENABLED ||
|
||||
data[0] == WACOM_REPORT_PENABLED)
|
||||
return wacom_tpc_pen(wacom);
|
||||
}
|
||||
else if (wacom->touch_input) {
|
||||
dev_dbg(wacom->touch_input->dev.parent,
|
||||
"%s: received report #%d\n", __func__, data[0]);
|
||||
|
||||
switch (len) {
|
||||
case WACOM_PKGLEN_TPC1FG:
|
||||
return wacom_tpc_single_touch(wacom, len);
|
||||
|
||||
case WACOM_PKGLEN_TPC2FG:
|
||||
return wacom_tpc_mt_touch(wacom);
|
||||
|
||||
case WACOM_PKGLEN_PENABLED:
|
||||
return wacom_tpc_pen(wacom);
|
||||
|
||||
default:
|
||||
switch (data[0]) {
|
||||
case WACOM_REPORT_TPC1FG:
|
||||
case WACOM_REPORT_TPCHID:
|
||||
case WACOM_REPORT_TPCST:
|
||||
case WACOM_REPORT_TPC1FGE:
|
||||
switch (len) {
|
||||
case WACOM_PKGLEN_TPC1FG:
|
||||
return wacom_tpc_single_touch(wacom, len);
|
||||
|
||||
case WACOM_REPORT_TPCMT:
|
||||
case WACOM_REPORT_TPCMT2:
|
||||
return wacom_mt_touch(wacom);
|
||||
case WACOM_PKGLEN_TPC2FG:
|
||||
return wacom_tpc_mt_touch(wacom);
|
||||
|
||||
case WACOM_REPORT_PENABLED:
|
||||
return wacom_tpc_pen(wacom);
|
||||
default:
|
||||
switch (data[0]) {
|
||||
case WACOM_REPORT_TPC1FG:
|
||||
case WACOM_REPORT_TPCHID:
|
||||
case WACOM_REPORT_TPCST:
|
||||
case WACOM_REPORT_TPC1FGE:
|
||||
return wacom_tpc_single_touch(wacom, len);
|
||||
|
||||
case WACOM_REPORT_TPCMT:
|
||||
case WACOM_REPORT_TPCMT2:
|
||||
return wacom_mt_touch(wacom);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,22 +178,39 @@ static int usb_read(struct i2c_adapter *adapter, int cmd,
|
||||
int value, int index, void *data, int len)
|
||||
{
|
||||
struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
|
||||
void *dmadata = kmalloc(len, GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (!dmadata)
|
||||
return -ENOMEM;
|
||||
|
||||
/* do control transfer */
|
||||
return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
|
||||
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
|
||||
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
|
||||
USB_DIR_IN, value, index, data, len, 2000);
|
||||
USB_DIR_IN, value, index, dmadata, len, 2000);
|
||||
|
||||
memcpy(data, dmadata, len);
|
||||
kfree(dmadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_write(struct i2c_adapter *adapter, int cmd,
|
||||
int value, int index, void *data, int len)
|
||||
{
|
||||
struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
|
||||
void *dmadata = kmemdup(data, len, GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (!dmadata)
|
||||
return -ENOMEM;
|
||||
|
||||
/* do control transfer */
|
||||
return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
|
||||
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
|
||||
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
value, index, data, len, 2000);
|
||||
value, index, dmadata, len, 2000);
|
||||
|
||||
kfree(dmadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
|
||||
|
||||
@@ -156,7 +156,8 @@ static const struct sdhci_ops sdhci_iproc_ops = {
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
|
||||
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
|
||||
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
|
||||
SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
|
||||
.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,
|
||||
.ops = &sdhci_iproc_ops,
|
||||
};
|
||||
|
||||
@@ -5260,9 +5260,11 @@ static netdev_features_t be_features_check(struct sk_buff *skb,
|
||||
struct be_adapter *adapter = netdev_priv(dev);
|
||||
u8 l4_hdr = 0;
|
||||
|
||||
/* The code below restricts offload features for some tunneled packets.
|
||||
/* The code below restricts offload features for some tunneled and
|
||||
* Q-in-Q packets.
|
||||
* Offload features for normal (non tunnel) packets are unchanged.
|
||||
*/
|
||||
features = vlan_features_check(skb, features);
|
||||
if (!skb->encapsulation ||
|
||||
!(adapter->flags & BE_FLAGS_VXLAN_OFFLOADS))
|
||||
return features;
|
||||
|
||||
@@ -203,34 +203,6 @@ static int marvell_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* The Marvell PHY has an errata which requires
|
||||
* that certain registers get written in order
|
||||
* to restart autonegotiation */
|
||||
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x1f);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x200c);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x5);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = marvell_set_polarity(phydev, phydev->mdix);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -264,6 +236,42 @@ static int marvell_config_aneg(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m88e1101_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* This Marvell PHY has an errata which requires
|
||||
* that certain registers get written in order
|
||||
* to restart autonegotiation
|
||||
*/
|
||||
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x1f);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x200c);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x5);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return marvell_config_aneg(phydev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_MDIO
|
||||
/*
|
||||
* Set and/or override some configuration registers based on the
|
||||
@@ -993,7 +1001,7 @@ static struct phy_driver marvell_drivers[] = {
|
||||
.name = "Marvell 88E1101",
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.flags = PHY_HAS_INTERRUPT,
|
||||
.config_aneg = &marvell_config_aneg,
|
||||
.config_aneg = &m88e1101_config_aneg,
|
||||
.read_status = &genphy_read_status,
|
||||
.ack_interrupt = &marvell_ack_interrupt,
|
||||
.config_intr = &marvell_config_intr,
|
||||
|
||||
@@ -730,6 +730,8 @@ static const struct usb_device_id products[] = {
|
||||
{QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx */
|
||||
{QMI_FIXED_INTF(0x1199, 0x9079, 8)}, /* Sierra Wireless EM74xx */
|
||||
{QMI_FIXED_INTF(0x1199, 0x9079, 10)}, /* Sierra Wireless EM74xx */
|
||||
{QMI_FIXED_INTF(0x1199, 0x907b, 8)}, /* Sierra Wireless EM74xx */
|
||||
{QMI_FIXED_INTF(0x1199, 0x907b, 10)}, /* Sierra Wireless EM74xx */
|
||||
{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
|
||||
{QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */
|
||||
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
|
||||
|
||||
@@ -1415,6 +1415,7 @@ static const struct net_device_ops virtnet_netdev = {
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
.ndo_busy_poll = virtnet_busy_poll,
|
||||
#endif
|
||||
.ndo_features_check = passthru_features_check,
|
||||
};
|
||||
|
||||
static void virtnet_config_changed_work(struct work_struct *work)
|
||||
|
||||
@@ -717,6 +717,7 @@ enum qeth_discipline_id {
|
||||
};
|
||||
|
||||
struct qeth_discipline {
|
||||
const struct device_type *devtype;
|
||||
void (*start_poll)(struct ccw_device *, int, unsigned long);
|
||||
qdio_handler_t *input_handler;
|
||||
qdio_handler_t *output_handler;
|
||||
@@ -881,6 +882,9 @@ extern struct qeth_discipline qeth_l2_discipline;
|
||||
extern struct qeth_discipline qeth_l3_discipline;
|
||||
extern const struct attribute_group *qeth_generic_attr_groups[];
|
||||
extern const struct attribute_group *qeth_osn_attr_groups[];
|
||||
extern const struct attribute_group qeth_device_attr_group;
|
||||
extern const struct attribute_group qeth_device_blkt_group;
|
||||
extern const struct device_type qeth_generic_devtype;
|
||||
extern struct workqueue_struct *qeth_wq;
|
||||
|
||||
int qeth_card_hw_is_reachable(struct qeth_card *);
|
||||
|
||||
@@ -5449,10 +5449,12 @@ void qeth_core_free_discipline(struct qeth_card *card)
|
||||
card->discipline = NULL;
|
||||
}
|
||||
|
||||
static const struct device_type qeth_generic_devtype = {
|
||||
const struct device_type qeth_generic_devtype = {
|
||||
.name = "qeth_generic",
|
||||
.groups = qeth_generic_attr_groups,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(qeth_generic_devtype);
|
||||
|
||||
static const struct device_type qeth_osn_devtype = {
|
||||
.name = "qeth_osn",
|
||||
.groups = qeth_osn_attr_groups,
|
||||
@@ -5578,23 +5580,22 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
|
||||
goto err_card;
|
||||
}
|
||||
|
||||
if (card->info.type == QETH_CARD_TYPE_OSN)
|
||||
gdev->dev.type = &qeth_osn_devtype;
|
||||
else
|
||||
gdev->dev.type = &qeth_generic_devtype;
|
||||
|
||||
switch (card->info.type) {
|
||||
case QETH_CARD_TYPE_OSN:
|
||||
case QETH_CARD_TYPE_OSM:
|
||||
rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
|
||||
if (rc)
|
||||
goto err_card;
|
||||
|
||||
gdev->dev.type = (card->info.type != QETH_CARD_TYPE_OSN)
|
||||
? card->discipline->devtype
|
||||
: &qeth_osn_devtype;
|
||||
rc = card->discipline->setup(card->gdev);
|
||||
if (rc)
|
||||
goto err_disc;
|
||||
case QETH_CARD_TYPE_OSD:
|
||||
case QETH_CARD_TYPE_OSX:
|
||||
break;
|
||||
default:
|
||||
gdev->dev.type = &qeth_generic_devtype;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5650,8 +5651,10 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev)
|
||||
if (rc)
|
||||
goto err;
|
||||
rc = card->discipline->setup(card->gdev);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
qeth_core_free_discipline(card);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
rc = card->discipline->set_online(gdev);
|
||||
err:
|
||||
|
||||
@@ -409,12 +409,16 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
|
||||
|
||||
if (card->options.layer2 == newdis)
|
||||
goto out;
|
||||
else {
|
||||
card->info.mac_bits = 0;
|
||||
if (card->discipline) {
|
||||
card->discipline->remove(card->gdev);
|
||||
qeth_core_free_discipline(card);
|
||||
}
|
||||
if (card->info.type == QETH_CARD_TYPE_OSM) {
|
||||
/* fixed layer, can't switch */
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
card->info.mac_bits = 0;
|
||||
if (card->discipline) {
|
||||
card->discipline->remove(card->gdev);
|
||||
qeth_core_free_discipline(card);
|
||||
}
|
||||
|
||||
rc = qeth_core_load_discipline(card, newdis);
|
||||
@@ -422,6 +426,8 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
|
||||
goto out;
|
||||
|
||||
rc = card->discipline->setup(card->gdev);
|
||||
if (rc)
|
||||
qeth_core_free_discipline(card);
|
||||
out:
|
||||
mutex_unlock(&card->discipline_mutex);
|
||||
return rc ? rc : count;
|
||||
@@ -699,10 +705,11 @@ static struct attribute *qeth_blkt_device_attrs[] = {
|
||||
&dev_attr_inter_jumbo.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group qeth_device_blkt_group = {
|
||||
const struct attribute_group qeth_device_blkt_group = {
|
||||
.name = "blkt",
|
||||
.attrs = qeth_blkt_device_attrs,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(qeth_device_blkt_group);
|
||||
|
||||
static struct attribute *qeth_device_attrs[] = {
|
||||
&dev_attr_state.attr,
|
||||
@@ -722,9 +729,10 @@ static struct attribute *qeth_device_attrs[] = {
|
||||
&dev_attr_switch_attrs.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group qeth_device_attr_group = {
|
||||
const struct attribute_group qeth_device_attr_group = {
|
||||
.attrs = qeth_device_attrs,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(qeth_device_attr_group);
|
||||
|
||||
const struct attribute_group *qeth_generic_attr_groups[] = {
|
||||
&qeth_device_attr_group,
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "qeth_core.h"
|
||||
|
||||
extern const struct attribute_group *qeth_l2_attr_groups[];
|
||||
|
||||
int qeth_l2_create_device_attributes(struct device *);
|
||||
void qeth_l2_remove_device_attributes(struct device *);
|
||||
void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
|
||||
|
||||
@@ -1027,11 +1027,21 @@ static int qeth_l2_stop(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct device_type qeth_l2_devtype = {
|
||||
.name = "qeth_layer2",
|
||||
.groups = qeth_l2_attr_groups,
|
||||
};
|
||||
|
||||
static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
|
||||
{
|
||||
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
|
||||
int rc;
|
||||
|
||||
qeth_l2_create_device_attributes(&gdev->dev);
|
||||
if (gdev->dev.type == &qeth_generic_devtype) {
|
||||
rc = qeth_l2_create_device_attributes(&gdev->dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
INIT_LIST_HEAD(&card->vid_list);
|
||||
hash_init(card->mac_htable);
|
||||
card->options.layer2 = 1;
|
||||
@@ -1043,7 +1053,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
|
||||
{
|
||||
struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
|
||||
|
||||
qeth_l2_remove_device_attributes(&cgdev->dev);
|
||||
if (cgdev->dev.type == &qeth_generic_devtype)
|
||||
qeth_l2_remove_device_attributes(&cgdev->dev);
|
||||
qeth_set_allowed_threads(card, 0, 1);
|
||||
wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
|
||||
|
||||
@@ -1101,7 +1112,6 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
|
||||
case QETH_CARD_TYPE_OSN:
|
||||
card->dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN,
|
||||
ether_setup);
|
||||
card->dev->flags |= IFF_NOARP;
|
||||
break;
|
||||
default:
|
||||
card->dev = alloc_etherdev(0);
|
||||
@@ -1114,9 +1124,12 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
|
||||
card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
|
||||
card->dev->mtu = card->info.initial_mtu;
|
||||
card->dev->netdev_ops = &qeth_l2_netdev_ops;
|
||||
card->dev->ethtool_ops =
|
||||
(card->info.type != QETH_CARD_TYPE_OSN) ?
|
||||
&qeth_l2_ethtool_ops : &qeth_l2_osn_ops;
|
||||
if (card->info.type == QETH_CARD_TYPE_OSN) {
|
||||
card->dev->ethtool_ops = &qeth_l2_osn_ops;
|
||||
card->dev->flags |= IFF_NOARP;
|
||||
} else {
|
||||
card->dev->ethtool_ops = &qeth_l2_ethtool_ops;
|
||||
}
|
||||
card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
|
||||
card->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
|
||||
@@ -1429,6 +1442,7 @@ static int qeth_l2_control_event(struct qeth_card *card,
|
||||
}
|
||||
|
||||
struct qeth_discipline qeth_l2_discipline = {
|
||||
.devtype = &qeth_l2_devtype,
|
||||
.start_poll = qeth_qdio_start_poll,
|
||||
.input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
|
||||
.output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
|
||||
|
||||
@@ -272,3 +272,11 @@ void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
|
||||
} else
|
||||
qeth_bridgeport_an_set(card, 0);
|
||||
}
|
||||
|
||||
const struct attribute_group *qeth_l2_attr_groups[] = {
|
||||
&qeth_device_attr_group,
|
||||
&qeth_device_blkt_group,
|
||||
/* l2 specific, see l2_{create,remove}_device_attributes(): */
|
||||
&qeth_l2_bridgeport_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -3227,8 +3227,11 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
|
||||
static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
|
||||
{
|
||||
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
|
||||
int rc;
|
||||
|
||||
qeth_l3_create_device_attributes(&gdev->dev);
|
||||
rc = qeth_l3_create_device_attributes(&gdev->dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
card->options.layer2 = 0;
|
||||
card->info.hwtrap = 0;
|
||||
return 0;
|
||||
@@ -3519,6 +3522,7 @@ static int qeth_l3_control_event(struct qeth_card *card,
|
||||
}
|
||||
|
||||
struct qeth_discipline qeth_l3_discipline = {
|
||||
.devtype = &qeth_generic_devtype,
|
||||
.start_poll = qeth_qdio_start_poll,
|
||||
.input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
|
||||
.output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
|
||||
|
||||
@@ -4452,6 +4452,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
|
||||
struct MPT3SAS_DEVICE *sas_device_priv_data;
|
||||
u32 response_code = 0;
|
||||
unsigned long flags;
|
||||
unsigned int sector_sz;
|
||||
|
||||
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
|
||||
scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
|
||||
@@ -4510,6 +4511,20 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
|
||||
}
|
||||
|
||||
xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
|
||||
|
||||
/* In case of bogus fw or device, we could end up having
|
||||
* unaligned partial completion. We can force alignment here,
|
||||
* then scsi-ml does not need to handle this misbehavior.
|
||||
*/
|
||||
sector_sz = scmd->device->sector_size;
|
||||
if (unlikely(scmd->request->cmd_type == REQ_TYPE_FS && sector_sz &&
|
||||
xfer_cnt % sector_sz)) {
|
||||
sdev_printk(KERN_INFO, scmd->device,
|
||||
"unaligned partial completion avoided (xfer_cnt=%u, sector_sz=%u)\n",
|
||||
xfer_cnt, sector_sz);
|
||||
xfer_cnt = round_down(xfer_cnt, sector_sz);
|
||||
}
|
||||
|
||||
scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
|
||||
if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
|
||||
log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
|
||||
|
||||
@@ -2179,8 +2179,10 @@ xfs_bmap_add_extent_delay_real(
|
||||
}
|
||||
temp = xfs_bmap_worst_indlen(bma->ip, temp);
|
||||
temp2 = xfs_bmap_worst_indlen(bma->ip, temp2);
|
||||
diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
|
||||
(bma->cur ? bma->cur->bc_private.b.allocated : 0));
|
||||
diff = (int)(temp + temp2 -
|
||||
(startblockval(PREV.br_startblock) -
|
||||
(bma->cur ?
|
||||
bma->cur->bc_private.b.allocated : 0)));
|
||||
if (diff > 0) {
|
||||
error = xfs_mod_fdblocks(bma->ip->i_mount,
|
||||
-((int64_t)diff), false);
|
||||
@@ -2232,7 +2234,6 @@ xfs_bmap_add_extent_delay_real(
|
||||
temp = da_new;
|
||||
if (bma->cur)
|
||||
temp += bma->cur->bc_private.b.allocated;
|
||||
ASSERT(temp <= da_old);
|
||||
if (temp < da_old)
|
||||
xfs_mod_fdblocks(bma->ip->i_mount,
|
||||
(int64_t)(da_old - temp), false);
|
||||
|
||||
@@ -4064,7 +4064,7 @@ xfs_btree_change_owner(
|
||||
xfs_btree_readahead_ptr(cur, ptr, 1);
|
||||
|
||||
/* save for the next iteration of the loop */
|
||||
lptr = *ptr;
|
||||
xfs_btree_copy_ptrs(cur, &lptr, ptr, 1);
|
||||
}
|
||||
|
||||
/* for each buffer in the level */
|
||||
|
||||
@@ -112,6 +112,7 @@ typedef struct attrlist_cursor_kern {
|
||||
*========================================================================*/
|
||||
|
||||
|
||||
/* Return 0 on success, or -errno; other state communicated via *context */
|
||||
typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int,
|
||||
unsigned char *, int, int, unsigned char *);
|
||||
|
||||
|
||||
@@ -108,16 +108,14 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
|
||||
(int)sfe->namelen,
|
||||
(int)sfe->valuelen,
|
||||
&sfe->nameval[sfe->namelen]);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
/*
|
||||
* Either search callback finished early or
|
||||
* didn't fit it all in the buffer after all.
|
||||
*/
|
||||
if (context->seen_enough)
|
||||
break;
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
|
||||
}
|
||||
trace_xfs_attr_list_sf_all(context);
|
||||
@@ -581,7 +579,7 @@ xfs_attr_put_listent(
|
||||
trace_xfs_attr_list_full(context);
|
||||
alist->al_more = 1;
|
||||
context->seen_enough = 1;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
aep = (attrlist_ent_t *)&context->alist[context->firstu];
|
||||
|
||||
@@ -682,7 +682,7 @@ xfs_getbmap(
|
||||
* extents.
|
||||
*/
|
||||
if (map[i].br_startblock == DELAYSTARTBLOCK &&
|
||||
map[i].br_startoff <= XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
|
||||
map[i].br_startoff < XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
|
||||
ASSERT((iflags & BMV_IF_DELALLOC) != 0);
|
||||
|
||||
if (map[i].br_startblock == HOLESTARTBLOCK &&
|
||||
|
||||
@@ -979,6 +979,8 @@ void
|
||||
xfs_buf_unlock(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
ASSERT(xfs_buf_islocked(bp));
|
||||
|
||||
XB_CLEAR_OWNER(bp);
|
||||
up(&bp->b_sema);
|
||||
|
||||
@@ -1712,6 +1714,28 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel a delayed write list.
|
||||
*
|
||||
* Remove each buffer from the list, clear the delwri queue flag and drop the
|
||||
* associated buffer reference.
|
||||
*/
|
||||
void
|
||||
xfs_buf_delwri_cancel(
|
||||
struct list_head *list)
|
||||
{
|
||||
struct xfs_buf *bp;
|
||||
|
||||
while (!list_empty(list)) {
|
||||
bp = list_first_entry(list, struct xfs_buf, b_list);
|
||||
|
||||
xfs_buf_lock(bp);
|
||||
bp->b_flags &= ~_XBF_DELWRI_Q;
|
||||
list_del_init(&bp->b_list);
|
||||
xfs_buf_relse(bp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a buffer to the delayed write list.
|
||||
*
|
||||
|
||||
@@ -304,6 +304,7 @@ extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
|
||||
extern void *xfs_buf_offset(struct xfs_buf *, size_t);
|
||||
|
||||
/* Delayed Write Buffer Routines */
|
||||
extern void xfs_buf_delwri_cancel(struct list_head *);
|
||||
extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *);
|
||||
extern int xfs_buf_delwri_submit(struct list_head *);
|
||||
extern int xfs_buf_delwri_submit_nowait(struct list_head *);
|
||||
|
||||
@@ -406,6 +406,7 @@ xfs_dir2_leaf_readbuf(
|
||||
|
||||
/*
|
||||
* Do we need more readahead?
|
||||
* Each loop tries to process 1 full dir blk; last may be partial.
|
||||
*/
|
||||
blk_start_plug(&plug);
|
||||
for (mip->ra_index = mip->ra_offset = i = 0;
|
||||
@@ -416,7 +417,8 @@ xfs_dir2_leaf_readbuf(
|
||||
* Read-ahead a contiguous directory block.
|
||||
*/
|
||||
if (i > mip->ra_current &&
|
||||
map[mip->ra_index].br_blockcount >= geo->fsbcount) {
|
||||
(map[mip->ra_index].br_blockcount - mip->ra_offset) >=
|
||||
geo->fsbcount) {
|
||||
xfs_dir3_data_readahead(dp,
|
||||
map[mip->ra_index].br_startoff + mip->ra_offset,
|
||||
XFS_FSB_TO_DADDR(dp->i_mount,
|
||||
@@ -437,14 +439,19 @@ xfs_dir2_leaf_readbuf(
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance offset through the mapping table.
|
||||
* Advance offset through the mapping table, processing a full
|
||||
* dir block even if it is fragmented into several extents.
|
||||
* But stop if we have consumed all valid mappings, even if
|
||||
* it's not yet a full directory block.
|
||||
*/
|
||||
for (j = 0; j < geo->fsbcount; j += length ) {
|
||||
for (j = 0;
|
||||
j < geo->fsbcount && mip->ra_index < mip->map_valid;
|
||||
j += length ) {
|
||||
/*
|
||||
* The rest of this extent but not more than a dir
|
||||
* block.
|
||||
*/
|
||||
length = min_t(int, geo->fsbcount,
|
||||
length = min_t(int, geo->fsbcount - j,
|
||||
map[mip->ra_index].br_blockcount -
|
||||
mip->ra_offset);
|
||||
mip->ra_offset += length;
|
||||
|
||||
@@ -1208,7 +1208,7 @@ xfs_find_get_desired_pgoff(
|
||||
unsigned nr_pages;
|
||||
unsigned int i;
|
||||
|
||||
want = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
|
||||
want = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1;
|
||||
nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
|
||||
want);
|
||||
/*
|
||||
@@ -1235,17 +1235,6 @@ xfs_find_get_desired_pgoff(
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* At lease we found one page. If this is the first time we
|
||||
* step into the loop, and if the first page index offset is
|
||||
* greater than the given search offset, a hole was found.
|
||||
*/
|
||||
if (type == HOLE_OFF && lastoff == startoff &&
|
||||
lastoff < page_offset(pvec.pages[0])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
loff_t b_offset;
|
||||
@@ -1257,18 +1246,18 @@ xfs_find_get_desired_pgoff(
|
||||
* file mapping. However, page->index will not change
|
||||
* because we have a reference on the page.
|
||||
*
|
||||
* Searching done if the page index is out of range.
|
||||
* If the current offset is not reaches the end of
|
||||
* the specified search range, there should be a hole
|
||||
* between them.
|
||||
* If current page offset is beyond where we've ended,
|
||||
* we've found a hole.
|
||||
*/
|
||||
if (page->index > end) {
|
||||
if (type == HOLE_OFF && lastoff < endoff) {
|
||||
*offset = lastoff;
|
||||
found = true;
|
||||
}
|
||||
if (type == HOLE_OFF && lastoff < endoff &&
|
||||
lastoff < page_offset(pvec.pages[i])) {
|
||||
found = true;
|
||||
*offset = lastoff;
|
||||
goto out;
|
||||
}
|
||||
/* Searching done if the page index is out of range. */
|
||||
if (page->index > end)
|
||||
goto out;
|
||||
|
||||
lock_page(page);
|
||||
/*
|
||||
|
||||
@@ -210,14 +210,17 @@ xfs_iget_cache_hit(
|
||||
|
||||
error = inode_init_always(mp->m_super, inode);
|
||||
if (error) {
|
||||
bool wake;
|
||||
/*
|
||||
* Re-initializing the inode failed, and we are in deep
|
||||
* trouble. Try to re-add it to the reclaim list.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
spin_lock(&ip->i_flags_lock);
|
||||
|
||||
wake = !!__xfs_iflags_test(ip, XFS_INEW);
|
||||
ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM);
|
||||
if (wake)
|
||||
wake_up_bit(&ip->i_flags, __XFS_INEW_BIT);
|
||||
ASSERT(ip->i_flags & XFS_IRECLAIMABLE);
|
||||
trace_xfs_iget_reclaim_fail(ip);
|
||||
goto out_error;
|
||||
@@ -363,6 +366,22 @@ out_destroy:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_inew_wait(
|
||||
struct xfs_inode *ip)
|
||||
{
|
||||
wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_INEW_BIT);
|
||||
DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_INEW_BIT);
|
||||
|
||||
do {
|
||||
prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
|
||||
if (!xfs_iflags_test(ip, XFS_INEW))
|
||||
break;
|
||||
schedule();
|
||||
} while (true);
|
||||
finish_wait(wq, &wait.wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an inode by number in the given file system.
|
||||
* The inode is looked up in the cache held in each AG.
|
||||
@@ -467,9 +486,11 @@ out_error_or_again:
|
||||
|
||||
STATIC int
|
||||
xfs_inode_ag_walk_grab(
|
||||
struct xfs_inode *ip)
|
||||
struct xfs_inode *ip,
|
||||
int flags)
|
||||
{
|
||||
struct inode *inode = VFS_I(ip);
|
||||
bool newinos = !!(flags & XFS_AGITER_INEW_WAIT);
|
||||
|
||||
ASSERT(rcu_read_lock_held());
|
||||
|
||||
@@ -487,7 +508,8 @@ xfs_inode_ag_walk_grab(
|
||||
goto out_unlock_noent;
|
||||
|
||||
/* avoid new or reclaimable inodes. Leave for reclaim code to flush */
|
||||
if (__xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIMABLE | XFS_IRECLAIM))
|
||||
if ((!newinos && __xfs_iflags_test(ip, XFS_INEW)) ||
|
||||
__xfs_iflags_test(ip, XFS_IRECLAIMABLE | XFS_IRECLAIM))
|
||||
goto out_unlock_noent;
|
||||
spin_unlock(&ip->i_flags_lock);
|
||||
|
||||
@@ -515,7 +537,8 @@ xfs_inode_ag_walk(
|
||||
void *args),
|
||||
int flags,
|
||||
void *args,
|
||||
int tag)
|
||||
int tag,
|
||||
int iter_flags)
|
||||
{
|
||||
uint32_t first_index;
|
||||
int last_error = 0;
|
||||
@@ -557,7 +580,7 @@ restart:
|
||||
for (i = 0; i < nr_found; i++) {
|
||||
struct xfs_inode *ip = batch[i];
|
||||
|
||||
if (done || xfs_inode_ag_walk_grab(ip))
|
||||
if (done || xfs_inode_ag_walk_grab(ip, iter_flags))
|
||||
batch[i] = NULL;
|
||||
|
||||
/*
|
||||
@@ -585,6 +608,9 @@ restart:
|
||||
for (i = 0; i < nr_found; i++) {
|
||||
if (!batch[i])
|
||||
continue;
|
||||
if ((iter_flags & XFS_AGITER_INEW_WAIT) &&
|
||||
xfs_iflags_test(batch[i], XFS_INEW))
|
||||
xfs_inew_wait(batch[i]);
|
||||
error = execute(batch[i], flags, args);
|
||||
IRELE(batch[i]);
|
||||
if (error == -EAGAIN) {
|
||||
@@ -637,12 +663,13 @@ xfs_eofblocks_worker(
|
||||
}
|
||||
|
||||
int
|
||||
xfs_inode_ag_iterator(
|
||||
xfs_inode_ag_iterator_flags(
|
||||
struct xfs_mount *mp,
|
||||
int (*execute)(struct xfs_inode *ip, int flags,
|
||||
void *args),
|
||||
int flags,
|
||||
void *args)
|
||||
void *args,
|
||||
int iter_flags)
|
||||
{
|
||||
struct xfs_perag *pag;
|
||||
int error = 0;
|
||||
@@ -652,7 +679,8 @@ xfs_inode_ag_iterator(
|
||||
ag = 0;
|
||||
while ((pag = xfs_perag_get(mp, ag))) {
|
||||
ag = pag->pag_agno + 1;
|
||||
error = xfs_inode_ag_walk(mp, pag, execute, flags, args, -1);
|
||||
error = xfs_inode_ag_walk(mp, pag, execute, flags, args, -1,
|
||||
iter_flags);
|
||||
xfs_perag_put(pag);
|
||||
if (error) {
|
||||
last_error = error;
|
||||
@@ -663,6 +691,17 @@ xfs_inode_ag_iterator(
|
||||
return last_error;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_inode_ag_iterator(
|
||||
struct xfs_mount *mp,
|
||||
int (*execute)(struct xfs_inode *ip, int flags,
|
||||
void *args),
|
||||
int flags,
|
||||
void *args)
|
||||
{
|
||||
return xfs_inode_ag_iterator_flags(mp, execute, flags, args, 0);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_inode_ag_iterator_tag(
|
||||
struct xfs_mount *mp,
|
||||
@@ -680,7 +719,8 @@ xfs_inode_ag_iterator_tag(
|
||||
ag = 0;
|
||||
while ((pag = xfs_perag_get_tag(mp, ag, tag))) {
|
||||
ag = pag->pag_agno + 1;
|
||||
error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag);
|
||||
error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag,
|
||||
0);
|
||||
xfs_perag_put(pag);
|
||||
if (error) {
|
||||
last_error = error;
|
||||
|
||||
@@ -48,6 +48,11 @@ struct xfs_eofblocks {
|
||||
#define XFS_IGET_UNTRUSTED 0x2
|
||||
#define XFS_IGET_DONTCACHE 0x4
|
||||
|
||||
/*
|
||||
* flags for AG inode iterator
|
||||
*/
|
||||
#define XFS_AGITER_INEW_WAIT 0x1 /* wait on new inodes */
|
||||
|
||||
int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino,
|
||||
uint flags, uint lock_flags, xfs_inode_t **ipp);
|
||||
|
||||
@@ -72,6 +77,9 @@ void xfs_eofblocks_worker(struct work_struct *);
|
||||
int xfs_inode_ag_iterator(struct xfs_mount *mp,
|
||||
int (*execute)(struct xfs_inode *ip, int flags, void *args),
|
||||
int flags, void *args);
|
||||
int xfs_inode_ag_iterator_flags(struct xfs_mount *mp,
|
||||
int (*execute)(struct xfs_inode *ip, int flags, void *args),
|
||||
int flags, void *args, int iter_flags);
|
||||
int xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
|
||||
int (*execute)(struct xfs_inode *ip, int flags, void *args),
|
||||
int flags, void *args, int tag);
|
||||
|
||||
@@ -208,7 +208,8 @@ xfs_get_initial_prid(struct xfs_inode *dp)
|
||||
#define XFS_IRECLAIM (1 << 0) /* started reclaiming this inode */
|
||||
#define XFS_ISTALE (1 << 1) /* inode has been staled */
|
||||
#define XFS_IRECLAIMABLE (1 << 2) /* inode can be reclaimed */
|
||||
#define XFS_INEW (1 << 3) /* inode has just been allocated */
|
||||
#define __XFS_INEW_BIT 3 /* inode has just been allocated */
|
||||
#define XFS_INEW (1 << __XFS_INEW_BIT)
|
||||
#define XFS_ITRUNCATED (1 << 5) /* truncated down so flush-on-close */
|
||||
#define XFS_IDIRTY_RELEASE (1 << 6) /* dirty release already seen */
|
||||
#define __XFS_IFLOCK_BIT 7 /* inode is being flushed right now */
|
||||
@@ -453,6 +454,7 @@ static inline void xfs_finish_inode_setup(struct xfs_inode *ip)
|
||||
xfs_iflags_clear(ip, XFS_INEW);
|
||||
barrier();
|
||||
unlock_new_inode(VFS_I(ip));
|
||||
wake_up_bit(&ip->i_flags, __XFS_INEW_BIT);
|
||||
}
|
||||
|
||||
static inline void xfs_setup_existing_inode(struct xfs_inode *ip)
|
||||
|
||||
@@ -403,6 +403,7 @@ xfs_attrlist_by_handle(
|
||||
{
|
||||
int error = -ENOMEM;
|
||||
attrlist_cursor_kern_t *cursor;
|
||||
struct xfs_fsop_attrlist_handlereq __user *p = arg;
|
||||
xfs_fsop_attrlist_handlereq_t al_hreq;
|
||||
struct dentry *dentry;
|
||||
char *kbuf;
|
||||
@@ -435,6 +436,11 @@ xfs_attrlist_by_handle(
|
||||
if (error)
|
||||
goto out_kfree;
|
||||
|
||||
if (copy_to_user(&p->pos, cursor, sizeof(attrlist_cursor_kern_t))) {
|
||||
error = -EFAULT;
|
||||
goto out_kfree;
|
||||
}
|
||||
|
||||
if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
|
||||
error = -EFAULT;
|
||||
|
||||
@@ -1379,10 +1385,11 @@ xfs_ioc_getbmap(
|
||||
unsigned int cmd,
|
||||
void __user *arg)
|
||||
{
|
||||
struct getbmapx bmx;
|
||||
struct getbmapx bmx = { 0 };
|
||||
int error;
|
||||
|
||||
if (copy_from_user(&bmx, arg, sizeof(struct getbmapx)))
|
||||
/* struct getbmap is a strict subset of struct getbmapx. */
|
||||
if (copy_from_user(&bmx, arg, offsetof(struct getbmapx, bmv_iflags)))
|
||||
return -EFAULT;
|
||||
|
||||
if (bmx.bmv_count < 2)
|
||||
|
||||
@@ -1355,12 +1355,7 @@ xfs_qm_quotacheck(
|
||||
mp->m_qflags |= flags;
|
||||
|
||||
error_return:
|
||||
while (!list_empty(&buffer_list)) {
|
||||
struct xfs_buf *bp =
|
||||
list_first_entry(&buffer_list, struct xfs_buf, b_list);
|
||||
list_del_init(&bp->b_list);
|
||||
xfs_buf_relse(bp);
|
||||
}
|
||||
xfs_buf_delwri_cancel(&buffer_list);
|
||||
|
||||
if (error) {
|
||||
xfs_warn(mp,
|
||||
|
||||
@@ -764,5 +764,6 @@ xfs_qm_dqrele_all_inodes(
|
||||
uint flags)
|
||||
{
|
||||
ASSERT(mp->m_quotainfo);
|
||||
xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags, NULL);
|
||||
xfs_inode_ag_iterator_flags(mp, xfs_dqrele_inode, flags, NULL,
|
||||
XFS_AGITER_INEW_WAIT);
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ xfs_xattr_put_listent(
|
||||
arraytop = context->count + prefix_len + namelen + 1;
|
||||
if (arraytop > context->firstu) {
|
||||
context->count = -1; /* insufficient space */
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
offset = (char *)context->alist + context->count;
|
||||
strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
|
||||
@@ -222,12 +222,15 @@ list_one_attr(const char *name, const size_t len, void *data,
|
||||
}
|
||||
|
||||
ssize_t
|
||||
xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
|
||||
xfs_vn_listxattr(
|
||||
struct dentry *dentry,
|
||||
char *data,
|
||||
size_t size)
|
||||
{
|
||||
struct xfs_attr_list_context context;
|
||||
struct attrlist_cursor_kern cursor = { 0 };
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int error;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int error;
|
||||
|
||||
/*
|
||||
* First read the regular on-disk attributes.
|
||||
@@ -245,7 +248,9 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
|
||||
else
|
||||
context.put_listent = xfs_xattr_put_listent_sizes;
|
||||
|
||||
xfs_attr_list_int(&context);
|
||||
error = xfs_attr_list_int(&context);
|
||||
if (error)
|
||||
return error;
|
||||
if (context.count < 0)
|
||||
return -ERANGE;
|
||||
|
||||
|
||||
@@ -616,15 +616,16 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
|
||||
static inline netdev_features_t vlan_features_check(const struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
if (skb_vlan_tagged_multi(skb))
|
||||
features = netdev_intersect_features(features,
|
||||
NETIF_F_SG |
|
||||
NETIF_F_HIGHDMA |
|
||||
NETIF_F_FRAGLIST |
|
||||
NETIF_F_GEN_CSUM |
|
||||
NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_STAG_TX);
|
||||
|
||||
if (skb_vlan_tagged_multi(skb)) {
|
||||
/* In the case of multi-tagged packets, use a direct mask
|
||||
* instead of using netdev_interesect_features(), to make
|
||||
* sure that only devices supporting NETIF_F_HW_CSUM will
|
||||
* have checksum offloading support.
|
||||
*/
|
||||
features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM |
|
||||
NETIF_F_FRAGLIST | NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_STAG_TX;
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,10 +110,16 @@ struct dst_entry {
|
||||
};
|
||||
};
|
||||
|
||||
struct dst_metrics {
|
||||
u32 metrics[RTAX_MAX];
|
||||
atomic_t refcnt;
|
||||
};
|
||||
extern const struct dst_metrics dst_default_metrics;
|
||||
|
||||
u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
|
||||
extern const u32 dst_default_metrics[];
|
||||
|
||||
#define DST_METRICS_READ_ONLY 0x1UL
|
||||
#define DST_METRICS_REFCOUNTED 0x2UL
|
||||
#define DST_METRICS_FLAGS 0x3UL
|
||||
#define __DST_METRICS_PTR(Y) \
|
||||
((u32 *)((Y) & ~DST_METRICS_FLAGS))
|
||||
|
||||
@@ -112,11 +112,11 @@ struct fib_info {
|
||||
unsigned char fib_type;
|
||||
__be32 fib_prefsrc;
|
||||
u32 fib_priority;
|
||||
u32 *fib_metrics;
|
||||
#define fib_mtu fib_metrics[RTAX_MTU-1]
|
||||
#define fib_window fib_metrics[RTAX_WINDOW-1]
|
||||
#define fib_rtt fib_metrics[RTAX_RTT-1]
|
||||
#define fib_advmss fib_metrics[RTAX_ADVMSS-1]
|
||||
struct dst_metrics *fib_metrics;
|
||||
#define fib_mtu fib_metrics->metrics[RTAX_MTU-1]
|
||||
#define fib_window fib_metrics->metrics[RTAX_WINDOW-1]
|
||||
#define fib_rtt fib_metrics->metrics[RTAX_RTT-1]
|
||||
#define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1]
|
||||
int fib_nhs;
|
||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
||||
int fib_weight;
|
||||
|
||||
@@ -1619,12 +1619,8 @@ static int soft_offline_huge_page(struct page *page, int flags)
|
||||
if (ret) {
|
||||
pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
|
||||
pfn, ret, page->flags);
|
||||
/*
|
||||
* We know that soft_offline_huge_page() tries to migrate
|
||||
* only one hugepage pointed to by hpage, so we need not
|
||||
* run through the pagelist here.
|
||||
*/
|
||||
putback_active_hugepage(hpage);
|
||||
if (!list_empty(&pagelist))
|
||||
putback_movable_pages(&pagelist);
|
||||
if (ret > 0)
|
||||
ret = -EIO;
|
||||
} else {
|
||||
|
||||
@@ -277,7 +277,7 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
|
||||
{
|
||||
int i;
|
||||
int nr = pagevec_count(pvec);
|
||||
int delta_munlocked;
|
||||
int delta_munlocked = -nr;
|
||||
struct pagevec pvec_putback;
|
||||
int pgrescued = 0;
|
||||
|
||||
@@ -297,6 +297,8 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
|
||||
continue;
|
||||
else
|
||||
__munlock_isolation_failed(page);
|
||||
} else {
|
||||
delta_munlocked++;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -308,7 +310,6 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
|
||||
pagevec_add(&pvec_putback, pvec->pages[i]);
|
||||
pvec->pages[i] = NULL;
|
||||
}
|
||||
delta_munlocked = -nr + pagevec_count(&pvec_putback);
|
||||
__mod_zone_page_state(zone, NR_MLOCK, delta_munlocked);
|
||||
spin_unlock_irq(&zone->lru_lock);
|
||||
|
||||
|
||||
@@ -5343,6 +5343,7 @@ static void memcg_propagate_slab_attrs(struct kmem_cache *s)
|
||||
char mbuf[64];
|
||||
char *buf;
|
||||
struct slab_attribute *attr = to_slab_attr(slab_attrs[i]);
|
||||
ssize_t len;
|
||||
|
||||
if (!attr || !attr->store || !attr->show)
|
||||
continue;
|
||||
@@ -5367,8 +5368,9 @@ static void memcg_propagate_slab_attrs(struct kmem_cache *s)
|
||||
buf = buffer;
|
||||
}
|
||||
|
||||
attr->show(root_cache, buf);
|
||||
attr->store(s, buf, strlen(buf));
|
||||
len = attr->show(root_cache, buf);
|
||||
if (len > 0)
|
||||
attr->store(s, buf, len);
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
|
||||
@@ -768,6 +768,13 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[])
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[IFLA_BR_VLAN_DEFAULT_PVID]) {
|
||||
__u16 defpvid = nla_get_u16(data[IFLA_BR_VLAN_DEFAULT_PVID]);
|
||||
|
||||
if (defpvid >= VLAN_VID_MASK)
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -166,6 +166,7 @@ static void br_stp_start(struct net_bridge *br)
|
||||
br_debug(br, "using kernel STP\n");
|
||||
|
||||
/* To start timers on any ports left in blocking */
|
||||
mod_timer(&br->hello_timer, jiffies + br->hello_time);
|
||||
br_port_state_selection(br);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ static void br_hello_timer_expired(unsigned long arg)
|
||||
if (br->dev->flags & IFF_UP) {
|
||||
br_config_bpdu_generation(br);
|
||||
|
||||
if (br->stp_enabled != BR_USER_STP)
|
||||
if (br->stp_enabled == BR_KERNEL_STP)
|
||||
mod_timer(&br->hello_timer,
|
||||
round_jiffies(jiffies + br->hello_time));
|
||||
}
|
||||
|
||||
@@ -151,13 +151,13 @@ int dst_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
}
|
||||
EXPORT_SYMBOL(dst_discard_out);
|
||||
|
||||
const u32 dst_default_metrics[RTAX_MAX + 1] = {
|
||||
const struct dst_metrics dst_default_metrics = {
|
||||
/* This initializer is needed to force linker to place this variable
|
||||
* into const section. Otherwise it might end into bss section.
|
||||
* We really want to avoid false sharing on this variable, and catch
|
||||
* any writes on it.
|
||||
*/
|
||||
[RTAX_MAX] = 0xdeadbeef,
|
||||
.refcnt = ATOMIC_INIT(1),
|
||||
};
|
||||
|
||||
void dst_init(struct dst_entry *dst, struct dst_ops *ops,
|
||||
@@ -169,7 +169,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
|
||||
if (dev)
|
||||
dev_hold(dev);
|
||||
dst->ops = ops;
|
||||
dst_init_metrics(dst, dst_default_metrics, true);
|
||||
dst_init_metrics(dst, dst_default_metrics.metrics, true);
|
||||
dst->expires = 0UL;
|
||||
dst->path = dst;
|
||||
dst->from = NULL;
|
||||
@@ -315,25 +315,30 @@ EXPORT_SYMBOL(dst_release);
|
||||
|
||||
u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old)
|
||||
{
|
||||
u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
|
||||
struct dst_metrics *p = kmalloc(sizeof(*p), GFP_ATOMIC);
|
||||
|
||||
if (p) {
|
||||
u32 *old_p = __DST_METRICS_PTR(old);
|
||||
struct dst_metrics *old_p = (struct dst_metrics *)__DST_METRICS_PTR(old);
|
||||
unsigned long prev, new;
|
||||
|
||||
memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
|
||||
atomic_set(&p->refcnt, 1);
|
||||
memcpy(p->metrics, old_p->metrics, sizeof(p->metrics));
|
||||
|
||||
new = (unsigned long) p;
|
||||
prev = cmpxchg(&dst->_metrics, old, new);
|
||||
|
||||
if (prev != old) {
|
||||
kfree(p);
|
||||
p = __DST_METRICS_PTR(prev);
|
||||
p = (struct dst_metrics *)__DST_METRICS_PTR(prev);
|
||||
if (prev & DST_METRICS_READ_ONLY)
|
||||
p = NULL;
|
||||
} else if (prev & DST_METRICS_REFCOUNTED) {
|
||||
if (atomic_dec_and_test(&old_p->refcnt))
|
||||
kfree(old_p);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
BUILD_BUG_ON(offsetof(struct dst_metrics, metrics) != 0);
|
||||
return (u32 *)p;
|
||||
}
|
||||
EXPORT_SYMBOL(dst_cow_metrics_generic);
|
||||
|
||||
@@ -342,7 +347,7 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
|
||||
{
|
||||
unsigned long prev, new;
|
||||
|
||||
new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY;
|
||||
new = ((unsigned long) &dst_default_metrics) | DST_METRICS_READ_ONLY;
|
||||
prev = cmpxchg(&dst->_metrics, old, new);
|
||||
if (prev == old)
|
||||
kfree(__DST_METRICS_PTR(old));
|
||||
|
||||
@@ -1458,13 +1458,13 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
cb->nlh->nlmsg_seq, 0,
|
||||
NLM_F_MULTI,
|
||||
ext_filter_mask);
|
||||
/* If we ran out of room on the first message,
|
||||
* we're in trouble
|
||||
*/
|
||||
WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
|
||||
|
||||
if (err < 0)
|
||||
goto out;
|
||||
if (err < 0) {
|
||||
if (likely(skb->len))
|
||||
goto out;
|
||||
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
|
||||
cont:
|
||||
@@ -1472,10 +1472,12 @@ cont:
|
||||
}
|
||||
}
|
||||
out:
|
||||
err = skb->len;
|
||||
out_err:
|
||||
cb->args[1] = idx;
|
||||
cb->args[0] = h;
|
||||
|
||||
return skb->len;
|
||||
return err;
|
||||
}
|
||||
|
||||
int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len)
|
||||
@@ -3127,8 +3129,12 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
err = br_dev->netdev_ops->ndo_bridge_getlink(
|
||||
skb, portid, seq, dev,
|
||||
filter_mask, NLM_F_MULTI);
|
||||
if (err < 0 && err != -EOPNOTSUPP)
|
||||
break;
|
||||
if (err < 0 && err != -EOPNOTSUPP) {
|
||||
if (likely(skb->len))
|
||||
break;
|
||||
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
@@ -3139,16 +3145,22 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
seq, dev,
|
||||
filter_mask,
|
||||
NLM_F_MULTI);
|
||||
if (err < 0 && err != -EOPNOTSUPP)
|
||||
break;
|
||||
if (err < 0 && err != -EOPNOTSUPP) {
|
||||
if (likely(skb->len))
|
||||
break;
|
||||
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
err = skb->len;
|
||||
out_err:
|
||||
rcu_read_unlock();
|
||||
cb->args[0] = idx;
|
||||
|
||||
return skb->len;
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline size_t bridge_nlmsg_size(void)
|
||||
|
||||
@@ -1690,17 +1690,17 @@ EXPORT_SYMBOL(skb_set_owner_w);
|
||||
|
||||
void skb_orphan_partial(struct sk_buff *skb)
|
||||
{
|
||||
/* TCP stack sets skb->ooo_okay based on sk_wmem_alloc,
|
||||
* so we do not completely orphan skb, but transfert all
|
||||
* accounted bytes but one, to avoid unexpected reorders.
|
||||
*/
|
||||
if (skb->destructor == sock_wfree
|
||||
#ifdef CONFIG_INET
|
||||
|| skb->destructor == tcp_wfree
|
||||
#endif
|
||||
) {
|
||||
atomic_sub(skb->truesize - 1, &skb->sk->sk_wmem_alloc);
|
||||
skb->truesize = 1;
|
||||
struct sock *sk = skb->sk;
|
||||
|
||||
if (atomic_inc_not_zero(&sk->sk_refcnt)) {
|
||||
atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
|
||||
skb->destructor = sock_efree;
|
||||
}
|
||||
} else {
|
||||
skb_orphan(skb);
|
||||
}
|
||||
|
||||
@@ -422,6 +422,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
|
||||
newsk->sk_backlog_rcv = dccp_v4_do_rcv;
|
||||
newnp->pktoptions = NULL;
|
||||
newnp->opt = NULL;
|
||||
newnp->ipv6_mc_list = NULL;
|
||||
newnp->ipv6_ac_list = NULL;
|
||||
newnp->ipv6_fl_list = NULL;
|
||||
newnp->mcast_oif = inet6_iif(skb);
|
||||
newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
|
||||
|
||||
@@ -486,6 +489,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
|
||||
/* Clone RX bits */
|
||||
newnp->rxopt.all = np->rxopt.all;
|
||||
|
||||
newnp->ipv6_mc_list = NULL;
|
||||
newnp->ipv6_ac_list = NULL;
|
||||
newnp->ipv6_fl_list = NULL;
|
||||
newnp->pktoptions = NULL;
|
||||
newnp->opt = NULL;
|
||||
newnp->mcast_oif = inet6_iif(skb);
|
||||
|
||||
@@ -757,7 +757,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
unsigned int e = 0, s_e;
|
||||
struct fib_table *tb;
|
||||
struct hlist_head *head;
|
||||
int dumped = 0;
|
||||
int dumped = 0, err;
|
||||
|
||||
if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
|
||||
((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
|
||||
@@ -777,20 +777,27 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (dumped)
|
||||
memset(&cb->args[2], 0, sizeof(cb->args) -
|
||||
2 * sizeof(cb->args[0]));
|
||||
if (fib_table_dump(tb, skb, cb) < 0)
|
||||
goto out;
|
||||
err = fib_table_dump(tb, skb, cb);
|
||||
if (err < 0) {
|
||||
if (likely(skb->len))
|
||||
goto out;
|
||||
|
||||
goto out_err;
|
||||
}
|
||||
dumped = 1;
|
||||
next:
|
||||
e++;
|
||||
}
|
||||
}
|
||||
out:
|
||||
err = skb->len;
|
||||
out_err:
|
||||
rcu_read_unlock();
|
||||
|
||||
cb->args[1] = e;
|
||||
cb->args[0] = h;
|
||||
|
||||
return skb->len;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Prepare and feed intra-kernel routing request.
|
||||
|
||||
@@ -204,6 +204,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
|
||||
static void free_fib_info_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct fib_info *fi = container_of(head, struct fib_info, rcu);
|
||||
struct dst_metrics *m;
|
||||
|
||||
change_nexthops(fi) {
|
||||
if (nexthop_nh->nh_dev)
|
||||
@@ -214,8 +215,9 @@ static void free_fib_info_rcu(struct rcu_head *head)
|
||||
rt_fibinfo_free(&nexthop_nh->nh_rth_input);
|
||||
} endfor_nexthops(fi);
|
||||
|
||||
if (fi->fib_metrics != (u32 *) dst_default_metrics)
|
||||
kfree(fi->fib_metrics);
|
||||
m = fi->fib_metrics;
|
||||
if (m != &dst_default_metrics && atomic_dec_and_test(&m->refcnt))
|
||||
kfree(m);
|
||||
kfree(fi);
|
||||
}
|
||||
|
||||
@@ -982,11 +984,11 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg)
|
||||
val = 255;
|
||||
if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
|
||||
return -EINVAL;
|
||||
fi->fib_metrics[type - 1] = val;
|
||||
fi->fib_metrics->metrics[type - 1] = val;
|
||||
}
|
||||
|
||||
if (ecn_ca)
|
||||
fi->fib_metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
|
||||
fi->fib_metrics->metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1044,11 +1046,12 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
|
||||
goto failure;
|
||||
fib_info_cnt++;
|
||||
if (cfg->fc_mx) {
|
||||
fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
|
||||
fi->fib_metrics = kzalloc(sizeof(*fi->fib_metrics), GFP_KERNEL);
|
||||
if (!fi->fib_metrics)
|
||||
goto failure;
|
||||
atomic_set(&fi->fib_metrics->refcnt, 1);
|
||||
} else
|
||||
fi->fib_metrics = (u32 *) dst_default_metrics;
|
||||
fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics;
|
||||
|
||||
fi->fib_net = net;
|
||||
fi->fib_protocol = cfg->fc_protocol;
|
||||
@@ -1251,7 +1254,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
||||
if (fi->fib_priority &&
|
||||
nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority))
|
||||
goto nla_put_failure;
|
||||
if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
|
||||
if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (fi->fib_prefsrc &&
|
||||
|
||||
@@ -1906,6 +1906,8 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
|
||||
|
||||
/* rcu_read_lock is hold by caller */
|
||||
hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
|
||||
int err;
|
||||
|
||||
if (i < s_i) {
|
||||
i++;
|
||||
continue;
|
||||
@@ -1916,17 +1918,14 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
RTM_NEWROUTE,
|
||||
tb->tb_id,
|
||||
fa->fa_type,
|
||||
xkey,
|
||||
KEYLENGTH - fa->fa_slen,
|
||||
fa->fa_tos,
|
||||
fa->fa_info, NLM_F_MULTI) < 0) {
|
||||
err = fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
|
||||
tb->tb_id, fa->fa_type,
|
||||
xkey, KEYLENGTH - fa->fa_slen,
|
||||
fa->fa_tos, fa->fa_info, NLM_F_MULTI);
|
||||
if (err < 0) {
|
||||
cb->args[4] = i;
|
||||
return -1;
|
||||
return err;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -1948,10 +1947,13 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
|
||||
t_key key = cb->args[3];
|
||||
|
||||
while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
|
||||
if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
|
||||
int err;
|
||||
|
||||
err = fn_trie_dump_leaf(l, tb, skb, cb);
|
||||
if (err < 0) {
|
||||
cb->args[3] = key;
|
||||
cb->args[2] = count;
|
||||
return -1;
|
||||
return err;
|
||||
}
|
||||
|
||||
++count;
|
||||
|
||||
@@ -669,6 +669,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk,
|
||||
inet_sk(newsk)->inet_sport = htons(inet_rsk(req)->ir_num);
|
||||
newsk->sk_write_space = sk_stream_write_space;
|
||||
|
||||
inet_sk(newsk)->mc_list = NULL;
|
||||
|
||||
newsk->sk_mark = inet_rsk(req)->ir_mark;
|
||||
atomic64_set(&newsk->sk_cookie,
|
||||
atomic64_read(&inet_rsk(req)->ir_cookie));
|
||||
|
||||
@@ -1356,8 +1356,12 @@ static void rt_add_uncached_list(struct rtable *rt)
|
||||
|
||||
static void ipv4_dst_destroy(struct dst_entry *dst)
|
||||
{
|
||||
struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
|
||||
struct rtable *rt = (struct rtable *) dst;
|
||||
|
||||
if (p != &dst_default_metrics && atomic_dec_and_test(&p->refcnt))
|
||||
kfree(p);
|
||||
|
||||
if (!list_empty(&rt->rt_uncached)) {
|
||||
struct uncached_list *ul = rt->rt_uncached_list;
|
||||
|
||||
@@ -1409,7 +1413,11 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
|
||||
rt->rt_gateway = nh->nh_gw;
|
||||
rt->rt_uses_gateway = 1;
|
||||
}
|
||||
dst_init_metrics(&rt->dst, fi->fib_metrics, true);
|
||||
dst_init_metrics(&rt->dst, fi->fib_metrics->metrics, true);
|
||||
if (fi->fib_metrics != &dst_default_metrics) {
|
||||
rt->dst._metrics |= DST_METRICS_REFCOUNTED;
|
||||
atomic_inc(&fi->fib_metrics->refcnt);
|
||||
}
|
||||
#ifdef CONFIG_IP_ROUTE_CLASSID
|
||||
rt->dst.tclassid = nh->nh_tclassid;
|
||||
#endif
|
||||
|
||||
@@ -1071,9 +1071,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
|
||||
int *copied, size_t size)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct sockaddr *uaddr = msg->msg_name;
|
||||
int err, flags;
|
||||
|
||||
if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE))
|
||||
if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) ||
|
||||
(uaddr && msg->msg_namelen >= sizeof(uaddr->sa_family) &&
|
||||
uaddr->sa_family == AF_UNSPEC))
|
||||
return -EOPNOTSUPP;
|
||||
if (tp->fastopen_req)
|
||||
return -EALREADY; /* Another Fast Open is in progress */
|
||||
@@ -1086,7 +1089,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
|
||||
tp->fastopen_req->size = size;
|
||||
|
||||
flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
|
||||
err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
|
||||
err = __inet_stream_connect(sk->sk_socket, uaddr,
|
||||
msg->msg_namelen, flags);
|
||||
*copied = tp->fastopen_req->copied;
|
||||
tcp_free_fastopen_req(tp);
|
||||
|
||||
@@ -1134,13 +1134,14 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
|
||||
*/
|
||||
if (pkt_len > mss) {
|
||||
unsigned int new_len = (pkt_len / mss) * mss;
|
||||
if (!in_sack && new_len < pkt_len) {
|
||||
if (!in_sack && new_len < pkt_len)
|
||||
new_len += mss;
|
||||
if (new_len >= skb->len)
|
||||
return 0;
|
||||
}
|
||||
pkt_len = new_len;
|
||||
}
|
||||
|
||||
if (pkt_len >= skb->len && !in_sack)
|
||||
return 0;
|
||||
|
||||
err = tcp_fragment(sk, skb, pkt_len, mss, GFP_ATOMIC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -3219,7 +3220,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
|
||||
int delta;
|
||||
|
||||
/* Non-retransmitted hole got filled? That's reordering */
|
||||
if (reord < prior_fackets)
|
||||
if (reord < prior_fackets && reord <= tp->fackets_out)
|
||||
tcp_update_reordering(sk, tp->fackets_out - reord, 0);
|
||||
|
||||
delta = tcp_is_fack(tp) ? pkts_acked :
|
||||
|
||||
@@ -62,7 +62,6 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
|
||||
const struct net_offload *ops;
|
||||
int proto;
|
||||
struct frag_hdr *fptr;
|
||||
unsigned int unfrag_ip6hlen;
|
||||
u8 *prevhdr;
|
||||
int offset = 0;
|
||||
bool encap, udpfrag;
|
||||
@@ -121,8 +120,10 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
|
||||
skb->network_header = (u8 *)ipv6h - skb->head;
|
||||
|
||||
if (udpfrag) {
|
||||
unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
|
||||
int err = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
fptr = (struct frag_hdr *)((u8 *)ipv6h + err);
|
||||
fptr->frag_off = htons(offset);
|
||||
if (skb->next)
|
||||
fptr->frag_off |= htons(IP6_MF);
|
||||
|
||||
@@ -571,7 +571,10 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
int ptr, offset = 0, err = 0;
|
||||
u8 *prevhdr, nexthdr = 0;
|
||||
|
||||
hlen = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
err = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
hlen = err;
|
||||
nexthdr = *prevhdr;
|
||||
|
||||
mtu = ip6_skb_dst_mtu(skb);
|
||||
@@ -1429,6 +1432,11 @@ alloc_new_skb:
|
||||
*/
|
||||
alloclen += sizeof(struct frag_hdr);
|
||||
|
||||
copy = datalen - transhdrlen - fraggap;
|
||||
if (copy < 0) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (transhdrlen) {
|
||||
skb = sock_alloc_send_skb(sk,
|
||||
alloclen + hh_len,
|
||||
@@ -1478,13 +1486,9 @@ alloc_new_skb:
|
||||
data += fraggap;
|
||||
pskb_trim_unique(skb_prev, maxfraglen);
|
||||
}
|
||||
copy = datalen - transhdrlen - fraggap;
|
||||
|
||||
if (copy < 0) {
|
||||
err = -EINVAL;
|
||||
kfree_skb(skb);
|
||||
goto error;
|
||||
} else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
|
||||
if (copy > 0 &&
|
||||
getfrag(from, data + transhdrlen, offset,
|
||||
copy, fraggap, skb) < 0) {
|
||||
err = -EFAULT;
|
||||
kfree_skb(skb);
|
||||
goto error;
|
||||
|
||||
@@ -79,14 +79,13 @@ EXPORT_SYMBOL(ipv6_select_ident);
|
||||
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
||||
{
|
||||
u16 offset = sizeof(struct ipv6hdr);
|
||||
struct ipv6_opt_hdr *exthdr =
|
||||
(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
|
||||
unsigned int packet_len = skb_tail_pointer(skb) -
|
||||
skb_network_header(skb);
|
||||
int found_rhdr = 0;
|
||||
*nexthdr = &ipv6_hdr(skb)->nexthdr;
|
||||
|
||||
while (offset + 1 <= packet_len) {
|
||||
while (offset <= packet_len) {
|
||||
struct ipv6_opt_hdr *exthdr;
|
||||
|
||||
switch (**nexthdr) {
|
||||
|
||||
@@ -107,13 +106,16 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
||||
return offset;
|
||||
}
|
||||
|
||||
offset += ipv6_optlen(exthdr);
|
||||
*nexthdr = &exthdr->nexthdr;
|
||||
if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
|
||||
return -EINVAL;
|
||||
|
||||
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
|
||||
offset);
|
||||
offset += ipv6_optlen(exthdr);
|
||||
*nexthdr = &exthdr->nexthdr;
|
||||
}
|
||||
|
||||
return offset;
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(ip6_find_1stfragopt);
|
||||
|
||||
|
||||
@@ -1033,6 +1033,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
|
||||
newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
|
||||
#endif
|
||||
|
||||
newnp->ipv6_mc_list = NULL;
|
||||
newnp->ipv6_ac_list = NULL;
|
||||
newnp->ipv6_fl_list = NULL;
|
||||
newnp->pktoptions = NULL;
|
||||
@@ -1102,6 +1103,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
|
||||
First: no IPv4 options.
|
||||
*/
|
||||
newinet->inet_opt = NULL;
|
||||
newnp->ipv6_mc_list = NULL;
|
||||
newnp->ipv6_ac_list = NULL;
|
||||
newnp->ipv6_fl_list = NULL;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
|
||||
u8 frag_hdr_sz = sizeof(struct frag_hdr);
|
||||
__wsum csum;
|
||||
int tnl_hlen;
|
||||
int err;
|
||||
|
||||
mss = skb_shinfo(skb)->gso_size;
|
||||
if (unlikely(skb->len <= mss))
|
||||
@@ -97,7 +98,10 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
|
||||
/* Find the unfragmentable header and shift it left by frag_hdr_sz
|
||||
* bytes to insert fragment header.
|
||||
*/
|
||||
unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
err = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
unfrag_ip6hlen = err;
|
||||
nexthdr = *prevhdr;
|
||||
*prevhdr = NEXTHDR_FRAGMENT;
|
||||
unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
|
||||
|
||||
@@ -472,15 +472,14 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
|
||||
struct sctp_association **app,
|
||||
struct sctp_transport **tpp)
|
||||
{
|
||||
struct sctp_init_chunk *chunkhdr, _chunkhdr;
|
||||
union sctp_addr saddr;
|
||||
union sctp_addr daddr;
|
||||
struct sctp_af *af;
|
||||
struct sock *sk = NULL;
|
||||
struct sctp_association *asoc;
|
||||
struct sctp_transport *transport = NULL;
|
||||
struct sctp_init_chunk *chunkhdr;
|
||||
__u32 vtag = ntohl(sctphdr->vtag);
|
||||
int len = skb->len - ((void *)sctphdr - (void *)skb->data);
|
||||
|
||||
*app = NULL; *tpp = NULL;
|
||||
|
||||
@@ -515,13 +514,16 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
|
||||
* discard the packet.
|
||||
*/
|
||||
if (vtag == 0) {
|
||||
chunkhdr = (void *)sctphdr + sizeof(struct sctphdr);
|
||||
if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t)
|
||||
+ sizeof(__be32) ||
|
||||
/* chunk header + first 4 octects of init header */
|
||||
chunkhdr = skb_header_pointer(skb, skb_transport_offset(skb) +
|
||||
sizeof(struct sctphdr),
|
||||
sizeof(struct sctp_chunkhdr) +
|
||||
sizeof(__be32), &_chunkhdr);
|
||||
if (!chunkhdr ||
|
||||
chunkhdr->chunk_hdr.type != SCTP_CID_INIT ||
|
||||
ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) {
|
||||
ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag)
|
||||
goto out;
|
||||
}
|
||||
|
||||
} else if (vtag != asoc->c.peer_vtag) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -239,12 +239,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
struct sctp_bind_addr *bp;
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct sctp_sockaddr_entry *laddr;
|
||||
union sctp_addr *baddr = NULL;
|
||||
union sctp_addr *daddr = &t->ipaddr;
|
||||
union sctp_addr dst_saddr;
|
||||
struct in6_addr *final_p, final;
|
||||
__u8 matchlen = 0;
|
||||
__u8 bmatchlen;
|
||||
sctp_scope_t scope;
|
||||
|
||||
memset(fl6, 0, sizeof(struct flowi6));
|
||||
@@ -311,23 +309,37 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
*/
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
|
||||
if (!laddr->valid)
|
||||
struct dst_entry *bdst;
|
||||
__u8 bmatchlen;
|
||||
|
||||
if (!laddr->valid ||
|
||||
laddr->state != SCTP_ADDR_SRC ||
|
||||
laddr->a.sa.sa_family != AF_INET6 ||
|
||||
scope > sctp_scope(&laddr->a))
|
||||
continue;
|
||||
if ((laddr->state == SCTP_ADDR_SRC) &&
|
||||
(laddr->a.sa.sa_family == AF_INET6) &&
|
||||
(scope <= sctp_scope(&laddr->a))) {
|
||||
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
|
||||
if (!baddr || (matchlen < bmatchlen)) {
|
||||
baddr = &laddr->a;
|
||||
matchlen = bmatchlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (baddr) {
|
||||
fl6->saddr = baddr->v6.sin6_addr;
|
||||
fl6->fl6_sport = baddr->v6.sin6_port;
|
||||
|
||||
fl6->saddr = laddr->a.v6.sin6_addr;
|
||||
fl6->fl6_sport = laddr->a.v6.sin6_port;
|
||||
final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
|
||||
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
|
||||
bdst = ip6_dst_lookup_flow(sk, fl6, final_p);
|
||||
|
||||
if (!IS_ERR(bdst) &&
|
||||
ipv6_chk_addr(dev_net(bdst->dev),
|
||||
&laddr->a.v6.sin6_addr, bdst->dev, 1)) {
|
||||
if (!IS_ERR_OR_NULL(dst))
|
||||
dst_release(dst);
|
||||
dst = bdst;
|
||||
break;
|
||||
}
|
||||
|
||||
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
|
||||
if (matchlen > bmatchlen)
|
||||
continue;
|
||||
|
||||
if (!IS_ERR_OR_NULL(dst))
|
||||
dst_release(dst);
|
||||
dst = bdst;
|
||||
matchlen = bmatchlen;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -662,6 +674,9 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
|
||||
newnp = inet6_sk(newsk);
|
||||
|
||||
memcpy(newnp, np, sizeof(struct ipv6_pinfo));
|
||||
newnp->ipv6_mc_list = NULL;
|
||||
newnp->ipv6_ac_list = NULL;
|
||||
newnp->ipv6_fl_list = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
opt = rcu_dereference(np->opt);
|
||||
|
||||
@@ -1537,6 +1537,8 @@ static const struct snd_pci_quirk stac9200_fixup_tbl[] = {
|
||||
"Dell Inspiron 1501", STAC_9200_DELL_M26),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
|
||||
"unknown Dell", STAC_9200_DELL_M26),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0201,
|
||||
"Dell Latitude D430", STAC_9200_DELL_M22),
|
||||
/* Panasonic */
|
||||
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
|
||||
/* Gateway machines needs EAPD to be set on resume */
|
||||
|
||||
Reference in New Issue
Block a user