commit: 2f058c9e753dbef7a468d79a3e2994a336bc00bf Author: Mike Pagano <mpagano <AT> gentoo <DOT> org> AuthorDate: Thu Nov 2 10:03:48 2017 +0000 Commit: Mike Pagano <mpagano <AT> gentoo <DOT> org> CommitDate: Thu Nov 2 10:03:48 2017 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=2f058c9e
Linux patch 4.9.60 0000_README | 4 + 1059_linux-4.9.60.patch | 959 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 963 insertions(+) diff --git a/0000_README b/0000_README index c92a6b6..1396f03 100644 --- a/0000_README +++ b/0000_README @@ -279,6 +279,10 @@ Patch: 1058_linux-4.9.59.patch From: http://www.kernel.org Desc: Linux 4.9.59 +Patch: 1059_linux-4.9.60.patch +From: http://www.kernel.org +Desc: Linux 4.9.60 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1059_linux-4.9.60.patch b/1059_linux-4.9.60.patch new file mode 100644 index 0000000..00218cc --- /dev/null +++ b/1059_linux-4.9.60.patch @@ -0,0 +1,959 @@ +diff --git a/Makefile b/Makefile +index 900cd7c3a9ee..2f7a386b1751 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 59 ++SUBLEVEL = 60 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c +index 70963c845e96..fc0df0f6fe88 100644 +--- a/arch/powerpc/kvm/powerpc.c ++++ b/arch/powerpc/kvm/powerpc.c +@@ -601,8 +601,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) + break; + #endif + case KVM_CAP_PPC_HTM: +- r = cpu_has_feature(CPU_FTR_TM_COMP) && +- is_kvmppc_hv_enabled(kvm); ++ r = cpu_has_feature(CPU_FTR_TM_COMP) && hv_enabled; + break; + default: + r = 0; +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +index 08cd0bd3ebe5..3907439417e7 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +@@ -825,7 +825,7 @@ uint32_t smu7_get_xclk(struct pp_hwmgr *hwmgr) + { + uint32_t reference_clock, tmp; + struct cgs_display_info info = {0}; +- struct cgs_mode_info mode_info; ++ struct cgs_mode_info mode_info = {0}; + + info.mode_info = &mode_info; + +@@ -3718,10 +3718,9 @@ int smu7_program_display_gap(struct pp_hwmgr *hwmgr) + uint32_t ref_clock; + uint32_t refresh_rate = 0; + struct cgs_display_info info = {0}; +- struct cgs_mode_info mode_info; ++ struct cgs_mode_info mode_info = {0}; + + info.mode_info = &mode_info; +- + cgs_get_active_displays_info(hwmgr->device, &info); + num_active_displays = info.display_count; + +@@ -3737,6 +3736,7 @@ int smu7_program_display_gap(struct pp_hwmgr *hwmgr) + frame_time_in_us = 1000000 / refresh_rate; + + pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us; ++ + data->frame_time_x2 = frame_time_in_us * 2 / 100; + + display_gap2 = pre_vbi_time_in_us * (ref_clock / 100); +diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c +index 681dce15fbc8..b8c50d883b2c 100644 +--- a/drivers/input/mouse/elan_i2c_core.c ++++ b/drivers/input/mouse/elan_i2c_core.c +@@ -1240,6 +1240,7 @@ static const struct acpi_device_id elan_acpi_id[] = { + { "ELAN0605", 0 }, + { "ELAN0609", 0 }, + { "ELAN060B", 0 }, ++ { "ELAN0611", 0 }, + { "ELAN1000", 0 }, + { } + }; +diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c +index abf09ac42ce4..339a0e2d2f86 100644 +--- a/drivers/input/tablet/gtco.c ++++ b/drivers/input/tablet/gtco.c +@@ -230,13 +230,17 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, + + /* Walk this report and pull out the info we need */ + while (i < length) { +- prefix = report[i]; +- +- /* Skip over prefix */ +- i++; ++ prefix = report[i++]; + + /* Determine data size and save the data in the proper variable */ +- size = PREF_SIZE(prefix); ++ size = (1U << PREF_SIZE(prefix)) >> 1; ++ if (i + size > length) { ++ dev_err(ddev, ++ "Not enough data (need %d, have %d)\n", ++ i + size, length); ++ break; ++ } ++ + switch (size) { + case 1: + data = report[i]; +@@ -244,8 +248,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, + case 2: + data16 = get_unaligned_le16(&report[i]); + break; +- case 3: +- size = 4; ++ case 4: + data32 = get_unaligned_le32(&report[i]); + break; + } +diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c +index 68ef0a4cd821..b0c80859f746 100644 +--- a/drivers/net/can/sun4i_can.c ++++ b/drivers/net/can/sun4i_can.c +@@ -342,7 +342,7 @@ static int sun4i_can_start(struct net_device *dev) + + /* enter the selected mode */ + mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); +- if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK) ++ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + mod_reg_val |= SUN4I_MSEL_LOOPBACK_MODE; + else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + mod_reg_val |= SUN4I_MSEL_LISTEN_ONLY_MODE; +@@ -811,7 +811,6 @@ static int sun4ican_probe(struct platform_device *pdev) + priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_LOOPBACK | +- CAN_CTRLMODE_PRESUME_ACK | + CAN_CTRLMODE_3_SAMPLES; + priv->base = addr; + priv->clk = clk; +diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c +index d51e0c401b48..4224e066cb16 100644 +--- a/drivers/net/can/usb/kvaser_usb.c ++++ b/drivers/net/can/usb/kvaser_usb.c +@@ -137,6 +137,7 @@ static inline bool kvaser_is_usbcan(const struct usb_device_id *id) + #define CMD_RESET_ERROR_COUNTER 49 + #define CMD_TX_ACKNOWLEDGE 50 + #define CMD_CAN_ERROR_EVENT 51 ++#define CMD_FLUSH_QUEUE_REPLY 68 + + #define CMD_LEAF_USB_THROTTLE 77 + #define CMD_LEAF_LOG_MESSAGE 106 +@@ -1301,6 +1302,11 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev, + goto warn; + break; + ++ case CMD_FLUSH_QUEUE_REPLY: ++ if (dev->family != KVASER_LEAF) ++ goto warn; ++ break; ++ + default: + warn: dev_warn(dev->udev->dev.parent, + "Unhandled message (%d)\n", msg->id); +@@ -1609,7 +1615,8 @@ static int kvaser_usb_close(struct net_device *netdev) + if (err) + netdev_warn(netdev, "Cannot flush queue, error %d\n", err); + +- if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel)) ++ err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel); ++ if (err) + netdev_warn(netdev, "Cannot reset card, error %d\n", err); + + err = kvaser_usb_stop_chip(priv); +diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c +index d7da81a875cf..c9af065feb28 100644 +--- a/drivers/regulator/fan53555.c ++++ b/drivers/regulator/fan53555.c +@@ -476,7 +476,10 @@ static const struct i2c_device_id fan53555_id[] = { + .name = "fan53555", + .driver_data = FAN53555_VENDOR_FAIRCHILD + }, { +- .name = "syr82x", ++ .name = "syr827", ++ .driver_data = FAN53555_VENDOR_SILERGY ++ }, { ++ .name = "syr828", + .driver_data = FAN53555_VENDOR_SILERGY + }, + { }, +diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c +index bcc8f3dfd4c4..b3f9243cfed5 100644 +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -358,6 +358,8 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) + + adapter->next_port_scan = jiffies; + ++ adapter->erp_action.adapter = adapter; ++ + if (zfcp_qdio_setup(adapter)) + goto failed; + +@@ -514,6 +516,9 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, + port->dev.groups = zfcp_port_attr_groups; + port->dev.release = zfcp_port_release; + ++ port->erp_action.adapter = adapter; ++ port->erp_action.port = port; ++ + if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) { + kfree(port); + goto err_out; +diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c +index 7ccfce559034..3b23d6754598 100644 +--- a/drivers/s390/scsi/zfcp_erp.c ++++ b/drivers/s390/scsi/zfcp_erp.c +@@ -193,9 +193,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, + &zfcp_sdev->status); + erp_action = &zfcp_sdev->erp_action; +- memset(erp_action, 0, sizeof(struct zfcp_erp_action)); +- erp_action->port = port; +- erp_action->sdev = sdev; ++ WARN_ON_ONCE(erp_action->port != port); ++ WARN_ON_ONCE(erp_action->sdev != sdev); + if (!(atomic_read(&zfcp_sdev->status) & + ZFCP_STATUS_COMMON_RUNNING)) + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; +@@ -208,8 +207,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, + zfcp_erp_action_dismiss_port(port); + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); + erp_action = &port->erp_action; +- memset(erp_action, 0, sizeof(struct zfcp_erp_action)); +- erp_action->port = port; ++ WARN_ON_ONCE(erp_action->port != port); ++ WARN_ON_ONCE(erp_action->sdev != NULL); + if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; + break; +@@ -219,7 +218,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, + zfcp_erp_action_dismiss_adapter(adapter); + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); + erp_action = &adapter->erp_action; +- memset(erp_action, 0, sizeof(struct zfcp_erp_action)); ++ WARN_ON_ONCE(erp_action->port != NULL); ++ WARN_ON_ONCE(erp_action->sdev != NULL); + if (!(atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_RUNNING)) + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; +@@ -229,7 +229,11 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, + return NULL; + } + +- erp_action->adapter = adapter; ++ WARN_ON_ONCE(erp_action->adapter != adapter); ++ memset(&erp_action->list, 0, sizeof(erp_action->list)); ++ memset(&erp_action->timer, 0, sizeof(erp_action->timer)); ++ erp_action->step = ZFCP_ERP_STEP_UNINITIALIZED; ++ erp_action->fsf_req_id = 0; + erp_action->action = need; + erp_action->status = act_status; + +diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c +index 9bd9b9a29dfc..a9b8104b982e 100644 +--- a/drivers/s390/scsi/zfcp_scsi.c ++++ b/drivers/s390/scsi/zfcp_scsi.c +@@ -115,10 +115,15 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) + struct zfcp_unit *unit; + int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE; + ++ zfcp_sdev->erp_action.adapter = adapter; ++ zfcp_sdev->erp_action.sdev = sdev; ++ + port = zfcp_get_port_by_wwpn(adapter, rport->port_name); + if (!port) + return -ENXIO; + ++ zfcp_sdev->erp_action.port = port; ++ + unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev)); + if (unit) + put_device(&unit->dev); +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 02dfbc1373e3..184c7db1e0ca 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -837,7 +837,7 @@ sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo) + + val = 0; + list_for_each_entry(srp, &sfp->rq_list, entry) { +- if (val > SG_MAX_QUEUE) ++ if (val >= SG_MAX_QUEUE) + break; + rinfo[val].req_state = srp->done + 1; + rinfo[val].problem = +diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c +index 14f9dea3173f..7d629b4e1ecc 100644 +--- a/drivers/spi/spi-bcm-qspi.c ++++ b/drivers/spi/spi-bcm-qspi.c +@@ -1215,7 +1215,7 @@ int bcm_qspi_probe(struct platform_device *pdev, + goto qspi_probe_err; + } + } else { +- goto qspi_probe_err; ++ goto qspi_resource_err; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi"); +@@ -1237,7 +1237,7 @@ int bcm_qspi_probe(struct platform_device *pdev, + qspi->base[CHIP_SELECT] = devm_ioremap_resource(dev, res); + if (IS_ERR(qspi->base[CHIP_SELECT])) { + ret = PTR_ERR(qspi->base[CHIP_SELECT]); +- goto qspi_probe_err; ++ goto qspi_resource_err; + } + } + +@@ -1245,7 +1245,7 @@ int bcm_qspi_probe(struct platform_device *pdev, + GFP_KERNEL); + if (!qspi->dev_ids) { + ret = -ENOMEM; +- goto qspi_probe_err; ++ goto qspi_resource_err; + } + + for (val = 0; val < num_irqs; val++) { +@@ -1334,8 +1334,9 @@ int bcm_qspi_probe(struct platform_device *pdev, + bcm_qspi_hw_uninit(qspi); + clk_disable_unprepare(qspi->clk); + qspi_probe_err: +- spi_master_put(master); + kfree(qspi->dev_ids); ++qspi_resource_err: ++ spi_master_put(master); + return ret; + } + /* probe function to be called by SoC specific platform driver probe */ +diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c +index 4a02c5c7df0d..0722f75f1d6a 100644 +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -412,15 +412,25 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) + GFP_NOWAIT); + if (!command) { + spin_unlock_irqrestore(&xhci->lock, flags); +- xhci_free_command(xhci, cmd); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto cmd_cleanup; ++ } + ++ ret = xhci_queue_stop_endpoint(xhci, command, slot_id, ++ i, suspend); ++ if (ret) { ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ xhci_free_command(xhci, command); ++ goto cmd_cleanup; + } +- xhci_queue_stop_endpoint(xhci, command, slot_id, i, +- suspend); + } + } +- xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend); ++ ret = xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend); ++ if (ret) { ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ goto cmd_cleanup; ++ } ++ + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + +@@ -431,6 +441,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) + xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n"); + ret = -ETIME; + } ++ ++cmd_cleanup: + xhci_free_command(xhci, cmd); + return ret; + } +diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c +index 2ef2b61b69df..79b8ab4c6663 100644 +--- a/drivers/xen/gntdev.c ++++ b/drivers/xen/gntdev.c +@@ -1030,6 +1030,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) + mutex_unlock(&priv->lock); + + if (use_ptemod) { ++ map->pages_vm_start = vma->vm_start; + err = apply_to_page_range(vma->vm_mm, vma->vm_start, + vma->vm_end - vma->vm_start, + find_grant_ptes, map); +@@ -1067,7 +1068,6 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) + set_grant_ptes_as_special, NULL); + } + #endif +- map->pages_vm_start = vma->vm_start; + } + + return 0; +diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c +index 03951f90ecf7..3e1c136aadb7 100644 +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -1900,6 +1900,7 @@ static int try_flush_caps(struct inode *inode, u64 *ptid) + retry: + spin_lock(&ci->i_ceph_lock); + if (ci->i_ceph_flags & CEPH_I_NOFLUSH) { ++ spin_unlock(&ci->i_ceph_lock); + dout("try_flush_caps skipping %p I_NOFLUSH set\n", inode); + goto out; + } +@@ -1917,8 +1918,10 @@ static int try_flush_caps(struct inode *inode, u64 *ptid) + mutex_lock(&session->s_mutex); + goto retry; + } +- if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) ++ if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) { ++ spin_unlock(&ci->i_ceph_lock); + goto out; ++ } + + flushing = __mark_caps_flushing(inode, session, true, + &flush_tid, &oldest_flush_tid); +diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h +index 599a29237cfe..a896e46671ea 100644 +--- a/fs/ecryptfs/ecryptfs_kernel.h ++++ b/fs/ecryptfs/ecryptfs_kernel.h +@@ -84,11 +84,16 @@ struct ecryptfs_page_crypt_context { + static inline struct ecryptfs_auth_tok * + ecryptfs_get_encrypted_key_payload_data(struct key *key) + { +- if (key->type == &key_type_encrypted) +- return (struct ecryptfs_auth_tok *) +- (&((struct encrypted_key_payload *)key->payload.data[0])->payload_data); +- else ++ struct encrypted_key_payload *payload; ++ ++ if (key->type != &key_type_encrypted) + return NULL; ++ ++ payload = key->payload.data[0]; ++ if (!payload) ++ return ERR_PTR(-EKEYREVOKED); ++ ++ return (struct ecryptfs_auth_tok *)payload->payload_data; + } + + static inline struct key *ecryptfs_get_encrypted_key(char *sig) +@@ -114,12 +119,17 @@ static inline struct ecryptfs_auth_tok * + ecryptfs_get_key_payload_data(struct key *key) + { + struct ecryptfs_auth_tok *auth_tok; ++ const struct user_key_payload *ukp; + + auth_tok = ecryptfs_get_encrypted_key_payload_data(key); +- if (!auth_tok) +- return (struct ecryptfs_auth_tok *)user_key_payload(key)->data; +- else ++ if (auth_tok) + return auth_tok; ++ ++ ukp = user_key_payload(key); ++ if (!ukp) ++ return ERR_PTR(-EKEYREVOKED); ++ ++ return (struct ecryptfs_auth_tok *)ukp->data; + } + + #define ECRYPTFS_MAX_KEYSET_SIZE 1024 +diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c +index 3cf1546dca82..fa218cd64f74 100644 +--- a/fs/ecryptfs/keystore.c ++++ b/fs/ecryptfs/keystore.c +@@ -459,7 +459,8 @@ static int ecryptfs_verify_version(u16 version) + * @auth_tok_key: key containing the authentication token + * @auth_tok: authentication token + * +- * Returns zero on valid auth tok; -EINVAL otherwise ++ * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or ++ * -EKEYREVOKED if the key was revoked before we acquired its semaphore. + */ + static int + ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, +@@ -468,6 +469,12 @@ ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, + int rc = 0; + + (*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key); ++ if (IS_ERR(*auth_tok)) { ++ rc = PTR_ERR(*auth_tok); ++ *auth_tok = NULL; ++ goto out; ++ } ++ + if (ecryptfs_verify_version((*auth_tok)->version)) { + printk(KERN_ERR "Data structure version mismatch. Userspace " + "tools must match eCryptfs kernel module with major " +diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c +index 642c57b8de7b..4bbad745415a 100644 +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -1312,7 +1312,8 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, + */ + over = !dir_emit(ctx, dirent->name, dirent->namelen, + dirent->ino, dirent->type); +- ctx->pos = dirent->off; ++ if (!over) ++ ctx->pos = dirent->off; + } + + buf += reclen; +diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h +index dd5f21e75805..856de39d0b89 100644 +--- a/include/uapi/linux/spi/spidev.h ++++ b/include/uapi/linux/spi/spidev.h +@@ -23,6 +23,7 @@ + #define SPIDEV_H + + #include <linux/types.h> ++#include <linux/ioctl.h> + + /* User space versions of kernel symbols for SPI clocking modes, + * matching <linux/spi/spi.h> +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 776dda02e751..296dcca77f33 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -68,6 +68,7 @@ enum { + * attach_mutex to avoid changing binding state while + * worker_attach_to_pool() is in progress. + */ ++ POOL_MANAGER_ACTIVE = 1 << 0, /* being managed */ + POOL_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */ + + /* worker flags */ +@@ -165,7 +166,6 @@ struct worker_pool { + /* L: hash of busy workers */ + + /* see manage_workers() for details on the two manager mutexes */ +- struct mutex manager_arb; /* manager arbitration */ + struct worker *manager; /* L: purely informational */ + struct mutex attach_mutex; /* attach/detach exclusion */ + struct list_head workers; /* A: attached workers */ +@@ -297,6 +297,7 @@ static struct workqueue_attrs *wq_update_unbound_numa_attrs_buf; + + static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ + static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */ ++static DECLARE_WAIT_QUEUE_HEAD(wq_manager_wait); /* wait for manager to go away */ + + static LIST_HEAD(workqueues); /* PR: list of all workqueues */ + static bool workqueue_freezing; /* PL: have wqs started freezing? */ +@@ -799,7 +800,7 @@ static bool need_to_create_worker(struct worker_pool *pool) + /* Do we have too many workers and should some go away? */ + static bool too_many_workers(struct worker_pool *pool) + { +- bool managing = mutex_is_locked(&pool->manager_arb); ++ bool managing = pool->flags & POOL_MANAGER_ACTIVE; + int nr_idle = pool->nr_idle + managing; /* manager is considered idle */ + int nr_busy = pool->nr_workers - nr_idle; + +@@ -1979,24 +1980,17 @@ static bool manage_workers(struct worker *worker) + { + struct worker_pool *pool = worker->pool; + +- /* +- * Anyone who successfully grabs manager_arb wins the arbitration +- * and becomes the manager. mutex_trylock() on pool->manager_arb +- * failure while holding pool->lock reliably indicates that someone +- * else is managing the pool and the worker which failed trylock +- * can proceed to executing work items. This means that anyone +- * grabbing manager_arb is responsible for actually performing +- * manager duties. If manager_arb is grabbed and released without +- * actual management, the pool may stall indefinitely. +- */ +- if (!mutex_trylock(&pool->manager_arb)) ++ if (pool->flags & POOL_MANAGER_ACTIVE) + return false; ++ ++ pool->flags |= POOL_MANAGER_ACTIVE; + pool->manager = worker; + + maybe_create_worker(pool); + + pool->manager = NULL; +- mutex_unlock(&pool->manager_arb); ++ pool->flags &= ~POOL_MANAGER_ACTIVE; ++ wake_up(&wq_manager_wait); + return true; + } + +@@ -3203,7 +3197,6 @@ static int init_worker_pool(struct worker_pool *pool) + setup_timer(&pool->mayday_timer, pool_mayday_timeout, + (unsigned long)pool); + +- mutex_init(&pool->manager_arb); + mutex_init(&pool->attach_mutex); + INIT_LIST_HEAD(&pool->workers); + +@@ -3273,13 +3266,15 @@ static void put_unbound_pool(struct worker_pool *pool) + hash_del(&pool->hash_node); + + /* +- * Become the manager and destroy all workers. Grabbing +- * manager_arb prevents @pool's workers from blocking on +- * attach_mutex. ++ * Become the manager and destroy all workers. This prevents ++ * @pool's workers from blocking on attach_mutex. We're the last ++ * manager and @pool gets freed with the flag set. + */ +- mutex_lock(&pool->manager_arb); +- + spin_lock_irq(&pool->lock); ++ wait_event_lock_irq(wq_manager_wait, ++ !(pool->flags & POOL_MANAGER_ACTIVE), pool->lock); ++ pool->flags |= POOL_MANAGER_ACTIVE; ++ + while ((worker = first_idle_worker(pool))) + destroy_worker(worker); + WARN_ON(pool->nr_workers || pool->nr_idle); +@@ -3293,8 +3288,6 @@ static void put_unbound_pool(struct worker_pool *pool) + if (pool->detach_completion) + wait_for_completion(pool->detach_completion); + +- mutex_unlock(&pool->manager_arb); +- + /* shut down the timers */ + del_timer_sync(&pool->idle_timer); + del_timer_sync(&pool->mayday_timer); +diff --git a/lib/assoc_array.c b/lib/assoc_array.c +index 59fd7c0b119c..5cd093589c5a 100644 +--- a/lib/assoc_array.c ++++ b/lib/assoc_array.c +@@ -598,21 +598,31 @@ static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit, + if ((edit->segment_cache[ASSOC_ARRAY_FAN_OUT] ^ base_seg) == 0) + goto all_leaves_cluster_together; + +- /* Otherwise we can just insert a new node ahead of the old +- * one. ++ /* Otherwise all the old leaves cluster in the same slot, but ++ * the new leaf wants to go into a different slot - so we ++ * create a new node (n0) to hold the new leaf and a pointer to ++ * a new node (n1) holding all the old leaves. ++ * ++ * This can be done by falling through to the node splitting ++ * path. + */ +- goto present_leaves_cluster_but_not_new_leaf; ++ pr_devel("present leaves cluster but not new leaf\n"); + } + + split_node: + pr_devel("split node\n"); + +- /* We need to split the current node; we know that the node doesn't +- * simply contain a full set of leaves that cluster together (it +- * contains meta pointers and/or non-clustering leaves). ++ /* We need to split the current node. The node must contain anything ++ * from a single leaf (in the one leaf case, this leaf will cluster ++ * with the new leaf) and the rest meta-pointers, to all leaves, some ++ * of which may cluster. ++ * ++ * It won't contain the case in which all the current leaves plus the ++ * new leaves want to cluster in the same slot. + * + * We need to expel at least two leaves out of a set consisting of the +- * leaves in the node and the new leaf. ++ * leaves in the node and the new leaf. The current meta pointers can ++ * just be copied as they shouldn't cluster with any of the leaves. + * + * We need a new node (n0) to replace the current one and a new node to + * take the expelled nodes (n1). +@@ -717,33 +727,6 @@ static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit, + pr_devel("<--%s() = ok [split node]\n", __func__); + return true; + +-present_leaves_cluster_but_not_new_leaf: +- /* All the old leaves cluster in the same slot, but the new leaf wants +- * to go into a different slot, so we create a new node to hold the new +- * leaf and a pointer to a new node holding all the old leaves. +- */ +- pr_devel("present leaves cluster but not new leaf\n"); +- +- new_n0->back_pointer = node->back_pointer; +- new_n0->parent_slot = node->parent_slot; +- new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch; +- new_n1->back_pointer = assoc_array_node_to_ptr(new_n0); +- new_n1->parent_slot = edit->segment_cache[0]; +- new_n1->nr_leaves_on_branch = node->nr_leaves_on_branch; +- edit->adjust_count_on = new_n0; +- +- for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) +- new_n1->slots[i] = node->slots[i]; +- +- new_n0->slots[edit->segment_cache[0]] = assoc_array_node_to_ptr(new_n0); +- edit->leaf_p = &new_n0->slots[edit->segment_cache[ASSOC_ARRAY_FAN_OUT]]; +- +- edit->set[0].ptr = &assoc_array_ptr_to_node(node->back_pointer)->slots[node->parent_slot]; +- edit->set[0].to = assoc_array_node_to_ptr(new_n0); +- edit->excised_meta[0] = assoc_array_node_to_ptr(node); +- pr_devel("<--%s() = ok [insert node before]\n", __func__); +- return true; +- + all_leaves_cluster_together: + /* All the leaves, new and old, want to cluster together in this node + * in the same slot, so we have to replace this node with a shortcut to +diff --git a/net/wireless/sme.c b/net/wireless/sme.c +index 35cc1de85dcc..6fd24f6435c3 100644 +--- a/net/wireless/sme.c ++++ b/net/wireless/sme.c +@@ -505,11 +505,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, + return -EOPNOTSUPP; + + if (wdev->current_bss) { +- if (!prev_bssid) +- return -EALREADY; +- if (prev_bssid && +- !ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid)) +- return -ENOTCONN; + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); + wdev->current_bss = NULL; +@@ -1025,11 +1020,35 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, + + ASSERT_WDEV_LOCK(wdev); + +- if (WARN_ON(wdev->connect_keys)) { +- kzfree(wdev->connect_keys); +- wdev->connect_keys = NULL; ++ /* ++ * If we have an ssid_len, we're trying to connect or are ++ * already connected, so reject a new SSID unless it's the ++ * same (which is the case for re-association.) ++ */ ++ if (wdev->ssid_len && ++ (wdev->ssid_len != connect->ssid_len || ++ memcmp(wdev->ssid, connect->ssid, wdev->ssid_len))) ++ return -EALREADY; ++ ++ /* ++ * If connected, reject (re-)association unless prev_bssid ++ * matches the current BSSID. ++ */ ++ if (wdev->current_bss) { ++ if (!prev_bssid) ++ return -EALREADY; ++ if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid)) ++ return -ENOTCONN; + } + ++ /* ++ * Reject if we're in the process of connecting with WEP, ++ * this case isn't very interesting and trying to handle ++ * it would make the code much more complex. ++ */ ++ if (wdev->connect_keys) ++ return -EINPROGRESS; ++ + cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, + rdev->wiphy.ht_capa_mod_mask); + +@@ -1080,7 +1099,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, + + if (err) { + wdev->connect_keys = NULL; +- wdev->ssid_len = 0; ++ /* ++ * This could be reassoc getting refused, don't clear ++ * ssid_len in that case. ++ */ ++ if (!wdev->current_bss) ++ wdev->ssid_len = 0; + return err; + } + +@@ -1105,5 +1129,13 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, + else if (wdev->current_bss) + err = rdev_disconnect(rdev, dev, reason); + ++ /* ++ * Clear ssid_len unless we actually were fully connected, ++ * in which case cfg80211_disconnected() will take care of ++ * this later. ++ */ ++ if (!wdev->current_bss) ++ wdev->ssid_len = 0; ++ + return err; + } +diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c +index a7e27e1140dd..22934885bd3f 100644 +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -1656,32 +1656,34 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr + + static int xfrm_dump_policy_done(struct netlink_callback *cb) + { +- struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; ++ struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; + struct net *net = sock_net(cb->skb->sk); + + xfrm_policy_walk_done(walk, net); + return 0; + } + ++static int xfrm_dump_policy_start(struct netlink_callback *cb) ++{ ++ struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; ++ ++ BUILD_BUG_ON(sizeof(*walk) > sizeof(cb->args)); ++ ++ xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); ++ return 0; ++} ++ + static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) + { + struct net *net = sock_net(skb->sk); +- struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; ++ struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; + struct xfrm_dump_info info; + +- BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > +- sizeof(cb->args) - sizeof(cb->args[0])); +- + info.in_skb = cb->skb; + info.out_skb = skb; + info.nlmsg_seq = cb->nlh->nlmsg_seq; + info.nlmsg_flags = NLM_F_MULTI; + +- if (!cb->args[0]) { +- cb->args[0] = 1; +- xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); +- } +- + (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); + + return skb->len; +@@ -2415,6 +2417,7 @@ static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { + + static const struct xfrm_link { + int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); ++ int (*start)(struct netlink_callback *); + int (*dump)(struct sk_buff *, struct netlink_callback *); + int (*done)(struct netlink_callback *); + const struct nla_policy *nla_pol; +@@ -2428,6 +2431,7 @@ static const struct xfrm_link { + [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, + [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, + [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, ++ .start = xfrm_dump_policy_start, + .dump = xfrm_dump_policy, + .done = xfrm_dump_policy_done }, + [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, +@@ -2479,6 +2483,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + + { + struct netlink_dump_control c = { ++ .start = link->start, + .dump = link->dump, + .done = link->done, + }; +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 6f337f00ba58..fe1d06d50392 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -329,6 +329,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0233: ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + case 0x10ec0282: +@@ -909,6 +910,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { + { 0x10ec0275, 0x1028, 0, "ALC3260" }, + { 0x10ec0899, 0x1028, 0, "ALC3861" }, + { 0x10ec0298, 0x1028, 0, "ALC3266" }, ++ { 0x10ec0236, 0x1028, 0, "ALC3204" }, + { 0x10ec0256, 0x1028, 0, "ALC3246" }, + { 0x10ec0225, 0x1028, 0, "ALC3253" }, + { 0x10ec0295, 0x1028, 0, "ALC3254" }, +@@ -3694,6 +3696,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) + alc_process_coef_fw(codec, coef0255_1); + alc_process_coef_fw(codec, coef0255); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0256); + alc_process_coef_fw(codec, coef0255); +@@ -3777,6 +3780,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, + + + switch (codec->core.vendor_id) { ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + alc_write_coef_idx(codec, 0x45, 0xc489); +@@ -3885,6 +3889,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) + case 0x10ec0295: + alc_process_coef_fw(codec, coef0225); + break; ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0255); +@@ -3971,6 +3976,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0256); + break; +@@ -4064,6 +4070,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0256); + break; +@@ -4131,6 +4138,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) + }; + + switch (codec->core.vendor_id) { ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0255); +@@ -4335,6 +4343,7 @@ static void alc255_set_default_jack_type(struct hda_codec *codec) + case 0x10ec0255: + alc_process_coef_fw(codec, alc255fw); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, alc256fw); + break; +@@ -5852,6 +5861,14 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + ALC225_STANDARD_PINS, + {0x12, 0xb7a60130}, + {0x1b, 0x90170110}), ++ SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ++ {0x12, 0x90a60140}, ++ {0x14, 0x90170110}, ++ {0x21, 0x02211020}), ++ SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ++ {0x12, 0x90a60140}, ++ {0x14, 0x90170150}, ++ {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x21, 0x02211020}), +@@ -6226,6 +6243,7 @@ static int patch_alc269(struct hda_codec *codec) + case 0x10ec0255: + spec->codec_variant = ALC269_TYPE_ALC255; + break; ++ case 0x10ec0236: + case 0x10ec0256: + spec->codec_variant = ALC269_TYPE_ALC256; + spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ +@@ -7205,6 +7223,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { + HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), ++ HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
