mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-26 16:51:48 +00:00
2203 lines
70 KiB
Diff
2203 lines
70 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index a5ecb29c6ed3..ad91a79aed51 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
VERSION = 4
|
|
PATCHLEVEL = 4
|
|
-SUBLEVEL = 70
|
|
+SUBLEVEL = 71
|
|
EXTRAVERSION =
|
|
NAME = Blurry Fish Butt
|
|
|
|
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
|
|
index 91b963a887b7..29c3b400f949 100644
|
|
--- a/arch/sparc/include/asm/pgtable_32.h
|
|
+++ b/arch/sparc/include/asm/pgtable_32.h
|
|
@@ -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
|
|
diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h
|
|
index 29d64b1758ed..be0cc1beed41 100644
|
|
--- a/arch/sparc/include/asm/setup.h
|
|
+++ b/arch/sparc/include/asm/setup.h
|
|
@@ -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)
|
|
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
|
|
index eb8287155279..3b7092d9ea8f 100644
|
|
--- a/arch/sparc/mm/init_32.c
|
|
+++ b/arch/sparc/mm/init_32.c
|
|
@@ -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;
|
|
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
|
|
index fc061f7c2bd1..a7de8ae185a5 100644
|
|
--- a/drivers/char/pcmcia/cm4040_cs.c
|
|
+++ b/drivers/char/pcmcia/cm4040_cs.c
|
|
@@ -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;
|
|
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
|
|
index ce0645d0c1e5..61e3a097a478 100644
|
|
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
|
|
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
|
|
@@ -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 */
|
|
}
|
|
}
|
|
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c
|
|
index 4a09947be244..3c32f095a873 100644
|
|
--- a/drivers/gpu/drm/radeon/ci_dpm.c
|
|
+++ b/drivers/gpu/drm/radeon/ci_dpm.c
|
|
@@ -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
|
|
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
|
|
index f81fb2641097..134874cab4c7 100644
|
|
--- a/drivers/gpu/drm/radeon/cik.c
|
|
+++ b/drivers/gpu/drm/radeon/cik.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
|
|
index 32491355a1d4..ba9e6ed4ae54 100644
|
|
--- a/drivers/gpu/drm/radeon/evergreen.c
|
|
+++ b/drivers/gpu/drm/radeon/evergreen.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
|
|
index cc2fdf0be37a..0e20c08f8977 100644
|
|
--- a/drivers/gpu/drm/radeon/r600.c
|
|
+++ b/drivers/gpu/drm/radeon/r600.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
|
|
index f878d6962da5..5cf3a2cbc07e 100644
|
|
--- a/drivers/gpu/drm/radeon/si.c
|
|
+++ b/drivers/gpu/drm/radeon/si.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
|
|
index 35e3fd9fadf6..b62c50d1b1e4 100644
|
|
--- a/drivers/hid/wacom_wac.c
|
|
+++ b/drivers/hid/wacom_wac.c
|
|
@@ -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);
|
|
+ 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_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:
|
|
+ return wacom_tpc_single_touch(wacom, len);
|
|
|
|
- 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);
|
|
+ case WACOM_REPORT_TPCMT:
|
|
+ case WACOM_REPORT_TPCMT2:
|
|
+ return wacom_mt_touch(wacom);
|
|
|
|
- case WACOM_REPORT_PENABLED:
|
|
- return wacom_tpc_pen(wacom);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
|
|
index 0ed77eeff31e..a2e3dd715380 100644
|
|
--- a/drivers/i2c/busses/i2c-tiny-usb.c
|
|
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
|
|
@@ -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)
|
|
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
|
|
index 3b423b0ad8e7..f280744578e4 100644
|
|
--- a/drivers/mmc/host/sdhci-iproc.c
|
|
+++ b/drivers/mmc/host/sdhci-iproc.c
|
|
@@ -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,
|
|
};
|
|
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
|
|
index 8a1d9fffd7d6..26255862d1cf 100644
|
|
--- a/drivers/net/ethernet/emulex/benet/be_main.c
|
|
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
|
|
@@ -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;
|
|
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
|
|
index c6f5d9a6bec6..582d8f0c6266 100644
|
|
--- a/drivers/net/usb/qmi_wwan.c
|
|
+++ b/drivers/net/usb/qmi_wwan.c
|
|
@@ -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 */
|
|
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
|
|
index 0e2a19e58923..7f7c87762bc6 100644
|
|
--- a/drivers/net/virtio_net.c
|
|
+++ b/drivers/net/virtio_net.c
|
|
@@ -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)
|
|
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
|
|
index 1766a20ebcb1..741f3ee81cfe 100644
|
|
--- a/drivers/s390/net/qeth_core.h
|
|
+++ b/drivers/s390/net/qeth_core.h
|
|
@@ -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 *);
|
|
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
|
|
index 31ac53fa5cee..d10bf3da8e5f 100644
|
|
--- a/drivers/s390/net/qeth_core_main.c
|
|
+++ b/drivers/s390/net/qeth_core_main.c
|
|
@@ -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:
|
|
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
|
|
index e6e5b9671bf2..fa844b0ff847 100644
|
|
--- a/drivers/s390/net/qeth_core_sys.c
|
|
+++ b/drivers/s390/net/qeth_core_sys.c
|
|
@@ -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,
|
|
diff --git a/drivers/s390/net/qeth_l2.h b/drivers/s390/net/qeth_l2.h
|
|
index 0767556404bd..eb87bf97d38a 100644
|
|
--- a/drivers/s390/net/qeth_l2.h
|
|
+++ b/drivers/s390/net/qeth_l2.h
|
|
@@ -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);
|
|
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
|
|
index df036b872b05..bf1e0e39334d 100644
|
|
--- a/drivers/s390/net/qeth_l2_main.c
|
|
+++ b/drivers/s390/net/qeth_l2_main.c
|
|
@@ -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,
|
|
diff --git a/drivers/s390/net/qeth_l2_sys.c b/drivers/s390/net/qeth_l2_sys.c
|
|
index 692db49e3d2a..a48ed9e7e168 100644
|
|
--- a/drivers/s390/net/qeth_l2_sys.c
|
|
+++ b/drivers/s390/net/qeth_l2_sys.c
|
|
@@ -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,
|
|
+};
|
|
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
|
|
index cc4d3c3d8cc5..285fe0b2c753 100644
|
|
--- a/drivers/s390/net/qeth_l3_main.c
|
|
+++ b/drivers/s390/net/qeth_l3_main.c
|
|
@@ -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,
|
|
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
|
|
index 8a5fbdb45cfd..e333029e4b6c 100644
|
|
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
|
|
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
|
|
@@ -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);
|
|
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
|
|
index 119c2422aac7..75884aecf920 100644
|
|
--- a/fs/xfs/libxfs/xfs_bmap.c
|
|
+++ b/fs/xfs/libxfs/xfs_bmap.c
|
|
@@ -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);
|
|
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
|
|
index af1bbee5586e..28bc5e78b110 100644
|
|
--- a/fs/xfs/libxfs/xfs_btree.c
|
|
+++ b/fs/xfs/libxfs/xfs_btree.c
|
|
@@ -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 */
|
|
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
|
|
index dd4824589470..234331227c0c 100644
|
|
--- a/fs/xfs/xfs_attr.h
|
|
+++ b/fs/xfs/xfs_attr.h
|
|
@@ -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 *);
|
|
|
|
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
|
|
index 4fa14820e2e2..c8be331a3196 100644
|
|
--- a/fs/xfs/xfs_attr_list.c
|
|
+++ b/fs/xfs/xfs_attr_list.c
|
|
@@ -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];
|
|
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
|
|
index 832764ee035a..863e1bff403b 100644
|
|
--- a/fs/xfs/xfs_bmap_util.c
|
|
+++ b/fs/xfs/xfs_bmap_util.c
|
|
@@ -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 &&
|
|
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
|
|
index 8146b0cf20ce..dcb70969ff1c 100644
|
|
--- a/fs/xfs/xfs_buf.c
|
|
+++ b/fs/xfs/xfs_buf.c
|
|
@@ -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);
|
|
|
|
@@ -1713,6 +1715,28 @@ error:
|
|
}
|
|
|
|
/*
|
|
+ * 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.
|
|
*
|
|
* This queues a buffer for writeout if it hasn't already been. Note that
|
|
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
|
|
index c75721acd867..149bbd451731 100644
|
|
--- a/fs/xfs/xfs_buf.h
|
|
+++ b/fs/xfs/xfs_buf.h
|
|
@@ -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 *);
|
|
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
|
|
index 642d55d10075..2fbf643fa10a 100644
|
|
--- a/fs/xfs/xfs_dir2_readdir.c
|
|
+++ b/fs/xfs/xfs_dir2_readdir.c
|
|
@@ -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;
|
|
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
|
|
index f5392ab2def1..ceea444dafb4 100644
|
|
--- a/fs/xfs/xfs_file.c
|
|
+++ b/fs/xfs/xfs_file.c
|
|
@@ -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);
|
|
/*
|
|
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
|
|
index d7a490f24ead..adbc1f59969a 100644
|
|
--- a/fs/xfs/xfs_icache.c
|
|
+++ b/fs/xfs/xfs_icache.c
|
|
@@ -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;
|
|
@@ -664,6 +692,17 @@ xfs_inode_ag_iterator(
|
|
}
|
|
|
|
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,
|
|
int (*execute)(struct xfs_inode *ip, int flags,
|
|
@@ -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;
|
|
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h
|
|
index 62f1f91c32cb..147a79212e63 100644
|
|
--- a/fs/xfs/xfs_icache.h
|
|
+++ b/fs/xfs/xfs_icache.h
|
|
@@ -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);
|
|
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
|
|
index ca9e11989cbd..ae1a49845744 100644
|
|
--- a/fs/xfs/xfs_inode.h
|
|
+++ b/fs/xfs/xfs_inode.h
|
|
@@ -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)
|
|
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
|
|
index d42738deec6d..e4a4f82ea13f 100644
|
|
--- a/fs/xfs/xfs_ioctl.c
|
|
+++ b/fs/xfs/xfs_ioctl.c
|
|
@@ -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)
|
|
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
|
|
index 532ab79d38fe..572b64a135b3 100644
|
|
--- a/fs/xfs/xfs_qm.c
|
|
+++ b/fs/xfs/xfs_qm.c
|
|
@@ -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,
|
|
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
|
|
index 3640c6e896af..4d334440bd94 100644
|
|
--- a/fs/xfs/xfs_qm_syscalls.c
|
|
+++ b/fs/xfs/xfs_qm_syscalls.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
|
|
index 839b35ca21c6..e6dae28dfa1a 100644
|
|
--- a/fs/xfs/xfs_xattr.c
|
|
+++ b/fs/xfs/xfs_xattr.c
|
|
@@ -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;
|
|
|
|
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
|
|
index 67ce5bd3b56a..19db03dbbd00 100644
|
|
--- a/include/linux/if_vlan.h
|
|
+++ b/include/linux/if_vlan.h
|
|
@@ -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;
|
|
}
|
|
|
|
diff --git a/include/net/dst.h b/include/net/dst.h
|
|
index c7329dcd90cc..e4f450617919 100644
|
|
--- a/include/net/dst.h
|
|
+++ b/include/net/dst.h
|
|
@@ -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))
|
|
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
|
|
index 3f98233388fb..bda1721e9622 100644
|
|
--- a/include/net/ip_fib.h
|
|
+++ b/include/net/ip_fib.h
|
|
@@ -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;
|
|
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
|
|
index 750b7893ee3a..43aee7ab143e 100644
|
|
--- a/mm/memory-failure.c
|
|
+++ b/mm/memory-failure.c
|
|
@@ -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 {
|
|
diff --git a/mm/mlock.c b/mm/mlock.c
|
|
index d6006b146fea..9d2e773f3a95 100644
|
|
--- a/mm/mlock.c
|
|
+++ b/mm/mlock.c
|
|
@@ -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);
|
|
|
|
diff --git a/mm/slub.c b/mm/slub.c
|
|
index 65d5f92d51d2..4cf3a9c768b1 100644
|
|
--- a/mm/slub.c
|
|
+++ b/mm/slub.c
|
|
@@ -5261,6 +5261,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;
|
|
@@ -5285,8 +5286,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)
|
|
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
|
|
index 413d18e37083..ff8bb41d713f 100644
|
|
--- a/net/bridge/br_netlink.c
|
|
+++ b/net/bridge/br_netlink.c
|
|
@@ -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;
|
|
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
|
|
index 8a7ada8bb947..57be733a99bc 100644
|
|
--- a/net/bridge/br_stp_if.c
|
|
+++ b/net/bridge/br_stp_if.c
|
|
@@ -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);
|
|
}
|
|
|
|
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
|
|
index 5f0f5af0ec35..7dbe6a5c31eb 100644
|
|
--- a/net/bridge/br_stp_timer.c
|
|
+++ b/net/bridge/br_stp_timer.c
|
|
@@ -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));
|
|
}
|
|
diff --git a/net/core/dst.c b/net/core/dst.c
|
|
index a1656e3b8d72..d7ad628bf64e 100644
|
|
--- a/net/core/dst.c
|
|
+++ b/net/core/dst.c
|
|
@@ -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));
|
|
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
|
|
index fe38ef58997c..d43544ce7550 100644
|
|
--- a/net/core/rtnetlink.c
|
|
+++ b/net/core/rtnetlink.c
|
|
@@ -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)
|
|
diff --git a/net/core/sock.c b/net/core/sock.c
|
|
index 9c708a5fb751..bd2fad27891e 100644
|
|
--- a/net/core/sock.c
|
|
+++ b/net/core/sock.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
|
|
index 8113ad58fcb4..3470ad1843bb 100644
|
|
--- a/net/dccp/ipv6.c
|
|
+++ b/net/dccp/ipv6.c
|
|
@@ -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);
|
|
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
|
|
index 1adba44f8fbc..66dcb529fd9c 100644
|
|
--- a/net/ipv4/fib_frontend.c
|
|
+++ b/net/ipv4/fib_frontend.c
|
|
@@ -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.
|
|
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
|
|
index 67d44aa9e09f..b2504712259f 100644
|
|
--- a/net/ipv4/fib_semantics.c
|
|
+++ b/net/ipv4/fib_semantics.c
|
|
@@ -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 &&
|
|
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
|
|
index 7c52afb98c42..5c598f99a500 100644
|
|
--- a/net/ipv4/fib_trie.c
|
|
+++ b/net/ipv4/fib_trie.c
|
|
@@ -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;
|
|
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
|
|
index 64148914803a..45fa2aaa3d3f 100644
|
|
--- a/net/ipv4/inet_connection_sock.c
|
|
+++ b/net/ipv4/inet_connection_sock.c
|
|
@@ -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));
|
|
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
|
|
index 375248b900ba..c295d882c6e0 100644
|
|
--- a/net/ipv4/route.c
|
|
+++ b/net/ipv4/route.c
|
|
@@ -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
|
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
|
index e1d51370977b..4bd8678329d6 100644
|
|
--- a/net/ipv4/tcp.c
|
|
+++ b/net/ipv4/tcp.c
|
|
@@ -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);
|
|
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
|
|
index 818630cec54f..87791f803627 100644
|
|
--- a/net/ipv4/tcp_input.c
|
|
+++ b/net/ipv4/tcp_input.c
|
|
@@ -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 :
|
|
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
|
|
index 225f5f7f26ba..568bc0a52ca1 100644
|
|
--- a/net/ipv6/ip6_offload.c
|
|
+++ b/net/ipv6/ip6_offload.c
|
|
@@ -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);
|
|
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
|
|
index 8004532fa882..1db17efe36c1 100644
|
|
--- a/net/ipv6/ip6_output.c
|
|
+++ b/net/ipv6/ip6_output.c
|
|
@@ -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;
|
|
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
|
|
index 1d184322a7b1..8b56c5240429 100644
|
|
--- a/net/ipv6/output_core.c
|
|
+++ b/net/ipv6/output_core.c
|
|
@@ -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);
|
|
|
|
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
|
|
index 1a63c4deef26..8e958fde6e4b 100644
|
|
--- a/net/ipv6/tcp_ipv6.c
|
|
+++ b/net/ipv6/tcp_ipv6.c
|
|
@@ -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;
|
|
|
|
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
|
|
index 7441e1e63893..01582966ffa0 100644
|
|
--- a/net/ipv6/udp_offload.c
|
|
+++ b/net/ipv6/udp_offload.c
|
|
@@ -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)) +
|
|
diff --git a/net/sctp/input.c b/net/sctp/input.c
|
|
index b6493b3f11a9..2d7859c03fd2 100644
|
|
--- a/net/sctp/input.c
|
|
+++ b/net/sctp/input.c
|
|
@@ -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;
|
|
}
|
|
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
|
|
index ce46f1c7f133..7527c168e471 100644
|
|
--- a/net/sctp/ipv6.c
|
|
+++ b/net/sctp/ipv6.c
|
|
@@ -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);
|
|
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
|
|
index 37b70f8e878f..0abab7926dca 100644
|
|
--- a/sound/pci/hda/patch_sigmatel.c
|
|
+++ b/sound/pci/hda/patch_sigmatel.c
|
|
@@ -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 */
|