已开启
fix CVEs for kernel_linux_6.6 master (#1024) #406
wanghao794创建于 7月24日
fix CVEs for kernel_linux_6.6 master (#1024) #406
已开启
共 49 个文件变更+493-354
| @@ -107,6 +107,8 @@ static long compat_restore_sigcontext(struct pt_regs *regs, | |||
| 107 | 107 | ||
| 108 | /* sc_regs is structured the same as the start of pt_regs */ | 108 | /* sc_regs is structured the same as the start of pt_regs */ |
| 109 | err = __copy_from_user(&cregs, &sc->sc_regs, sizeof(sc->sc_regs)); | 109 | err = __copy_from_user(&cregs, &sc->sc_regs, sizeof(sc->sc_regs)); |
| 110 | + if (unlikely(err)) | ||
| 111 | + return err; | ||
| 110 | 112 | ||
| 111 | cregs_to_regs(&cregs, regs); | 113 | cregs_to_regs(&cregs, regs); |
| 112 | 114 | ||
| @@ -327,8 +327,8 @@ static int compat_riscv_gpr_set(struct task_struct *target, | |||
| 327 | struct compat_user_regs_struct cregs; | 327 | struct compat_user_regs_struct cregs; |
| 328 | 328 | ||
| 329 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1); | 329 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1); |
| 330 | - | 330 | + if (!ret) |
| 331 | - cregs_to_regs(&cregs, task_pt_regs(target)); | 331 | + cregs_to_regs(&cregs, task_pt_regs(target)); |
| 332 | 332 | ||
| 333 | return ret; | 333 | return ret; |
| 334 | } | 334 | } |
| @@ -689,6 +689,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) | |||
| 689 | 689 | ||
| 690 | if (hci_register_dev(hdev) < 0) { | 690 | if (hci_register_dev(hdev) < 0) { |
| 691 | BT_ERR("Can't register HCI device"); | 691 | BT_ERR("Can't register HCI device"); |
| 692 | + percpu_down_write(&hu->proto_lock); | ||
| 693 | + clear_bit(HCI_UART_PROTO_INIT, &hu->flags); | ||
| 694 | + percpu_up_write(&hu->proto_lock); | ||
| 692 | hu->proto->close(hu); | 695 | hu->proto->close(hu); |
| 693 | hu->hdev = NULL; | 696 | hu->hdev = NULL; |
| 694 | hci_free_dev(hdev); | 697 | hci_free_dev(hdev); |
| @@ -178,7 +178,7 @@ static int mpfs_ccc_register_outputs(struct device *dev, struct mpfs_ccc_out_hw_ | |||
| 178 | return dev_err_probe(dev, ret, "failed to register clock id: %d\n", | 178 | return dev_err_probe(dev, ret, "failed to register clock id: %d\n", |
| 179 | out_hw->id); | 179 | out_hw->id); |
| 180 | 180 | ||
| 181 | - data->hw_data.hws[out_hw->id] = &out_hw->divider.hw; | 181 | + data->hw_data.hws[out_hw->id - 2] = &out_hw->divider.hw; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | return 0; | 184 | return 0; |
| @@ -234,6 +234,10 @@ static int mpfs_ccc_probe(struct platform_device *pdev) | |||
| 234 | unsigned int num_clks; | 234 | unsigned int num_clks; |
| 235 | int ret; | 235 | int ret; |
| 236 | 236 | ||
| 237 | + /* | ||
| 238 | + * If DLLs get added here, mpfs_ccc_register_outputs() currently packs | ||
| 239 | + * sparse clock IDs in the hws array | ||
| 240 | + */ | ||
| 237 | num_clks = ARRAY_SIZE(mpfs_ccc_pll_clks) + ARRAY_SIZE(mpfs_ccc_pll0out_clks) + | 241 | num_clks = ARRAY_SIZE(mpfs_ccc_pll_clks) + ARRAY_SIZE(mpfs_ccc_pll0out_clks) + |
| 238 | ARRAY_SIZE(mpfs_ccc_pll1out_clks); | 242 | ARRAY_SIZE(mpfs_ccc_pll1out_clks); |
| 239 | 243 | ||
| @@ -10138,6 +10138,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, | |||
| 10138 | } | 10138 | } |
| 10139 | 10139 | ||
| 10140 | if (dc_resource_is_dsc_encoding_supported(dc)) { | 10140 | if (dc_resource_is_dsc_encoding_supported(dc)) { |
| 10141 | + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { | ||
| 10142 | + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); | ||
| 10143 | + dm_new_crtc_state->mode_changed_independent_from_dsc = new_crtc_state->mode_changed; | ||
| 10144 | + } | ||
| 10145 | + | ||
| 10141 | for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { | 10146 | for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { |
| 10142 | if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { | 10147 | if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { |
| 10143 | ret = add_affected_mst_dsc_crtcs(state, crtc); | 10148 | ret = add_affected_mst_dsc_crtcs(state, crtc); |
| @@ -737,6 +737,7 @@ struct dm_crtc_state { | |||
| 737 | 737 | ||
| 738 | bool freesync_vrr_info_changed; | 738 | bool freesync_vrr_info_changed; |
| 739 | 739 | ||
| 740 | + bool mode_changed_independent_from_dsc; | ||
| 740 | bool dsc_force_changed; | 741 | bool dsc_force_changed; |
| 741 | bool vrr_supported; | 742 | bool vrr_supported; |
| 742 | struct mod_freesync_config freesync_config; | 743 | struct mod_freesync_config freesync_config; |
| @@ -1587,8 +1587,11 @@ int pre_validate_dsc(struct drm_atomic_state *state, | |||
| 1587 | } else { | 1587 | } else { |
| 1588 | int ind = find_crtc_index_in_state_by_stream(state, stream); | 1588 | int ind = find_crtc_index_in_state_by_stream(state, stream); |
| 1589 | 1589 | ||
| 1590 | - if (ind >= 0) | 1590 | + if (ind >= 0) { |
| 1591 | - state->crtcs[ind].new_state->mode_changed = 0; | 1591 | + struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(state->crtcs[ind].new_state); |
| 1592 | + | ||
| 1593 | + dm_new_crtc_state->base.mode_changed = dm_new_crtc_state->mode_changed_independent_from_dsc; | ||
| 1594 | + } | ||
| 1592 | } | 1595 | } |
| 1593 | } | 1596 | } |
| 1594 | clean_exit: | 1597 | clean_exit: |
| @@ -810,7 +810,7 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context) | |||
| 810 | bridge_attached = mhdp->bridge_attached; | 810 | bridge_attached = mhdp->bridge_attached; |
| 811 | spin_unlock(&mhdp->start_lock); | 811 | spin_unlock(&mhdp->start_lock); |
| 812 | if (bridge_attached) { | 812 | if (bridge_attached) { |
| 813 | - if (mhdp->connector.dev) | 813 | + if (mhdp->connector_ptr) |
| 814 | drm_kms_helper_hotplug_event(mhdp->bridge.dev); | 814 | drm_kms_helper_hotplug_event(mhdp->bridge.dev); |
| 815 | else | 815 | else |
| 816 | drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); | 816 | drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); |
| @@ -1709,6 +1709,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) | |||
| 1709 | return ret; | 1709 | return ret; |
| 1710 | } | 1710 | } |
| 1711 | 1711 | ||
| 1712 | + mhdp->connector_ptr = conn; | ||
| 1712 | drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs); | 1713 | drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs); |
| 1713 | 1714 | ||
| 1714 | ret = drm_display_info_set_bus_formats(&conn->display_info, | 1715 | ret = drm_display_info_set_bus_formats(&conn->display_info, |
| @@ -1988,17 +1989,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, | |||
| 1988 | struct drm_atomic_state *state = bridge_state->base.state; | 1989 | struct drm_atomic_state *state = bridge_state->base.state; |
| 1989 | struct cdns_mhdp_bridge_state *mhdp_state; | 1990 | struct cdns_mhdp_bridge_state *mhdp_state; |
| 1990 | struct drm_crtc_state *crtc_state; | 1991 | struct drm_crtc_state *crtc_state; |
| 1991 | - struct drm_connector *connector; | ||
| 1992 | struct drm_connector_state *conn_state; | 1992 | struct drm_connector_state *conn_state; |
| 1993 | struct drm_bridge_state *new_state; | 1993 | struct drm_bridge_state *new_state; |
| 1994 | const struct drm_display_mode *mode; | 1994 | const struct drm_display_mode *mode; |
| 1995 | u32 resp; | 1995 | u32 resp; |
| 1996 | - int ret; | 1996 | + int ret = 0; |
| 1997 | 1997 | ||
| 1998 | dev_dbg(mhdp->dev, "bridge enable\n"); | 1998 | dev_dbg(mhdp->dev, "bridge enable\n"); |
| 1999 | 1999 | ||
| 2000 | mutex_lock(&mhdp->link_mutex); | 2000 | mutex_lock(&mhdp->link_mutex); |
| 2001 | 2001 | ||
| 2002 | + mhdp->connector_ptr = drm_atomic_get_new_connector_for_encoder(state, | ||
| 2003 | + bridge->encoder); | ||
| 2004 | + if (WARN_ON(!mhdp->connector_ptr)) | ||
| 2005 | + goto out; | ||
| 2006 | + | ||
| 2007 | + conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector_ptr); | ||
| 2008 | + if (WARN_ON(!conn_state)) | ||
| 2009 | + goto out; | ||
| 2010 | + | ||
| 2002 | if (mhdp->plugged && !mhdp->link_up) { | 2011 | if (mhdp->plugged && !mhdp->link_up) { |
| 2003 | ret = cdns_mhdp_link_up(mhdp); | 2012 | ret = cdns_mhdp_link_up(mhdp); |
| 2004 | if (ret < 0) | 2013 | if (ret < 0) |
| @@ -2018,15 +2027,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, | |||
| 2018 | cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, | 2027 | cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, |
| 2019 | resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); | 2028 | resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); |
| 2020 | 2029 | ||
| 2021 | - connector = drm_atomic_get_new_connector_for_encoder(state, | ||
| 2022 | - bridge->encoder); | ||
| 2023 | - if (WARN_ON(!connector)) | ||
| 2024 | - goto out; | ||
| 2025 | - | ||
| 2026 | - conn_state = drm_atomic_get_new_connector_state(state, connector); | ||
| 2027 | - if (WARN_ON(!conn_state)) | ||
| 2028 | - goto out; | ||
| 2029 | - | ||
| 2030 | if (mhdp->hdcp_supported && | 2030 | if (mhdp->hdcp_supported && |
| 2031 | mhdp->hw_state == MHDP_HW_READY && | 2031 | mhdp->hw_state == MHDP_HW_READY && |
| 2032 | conn_state->content_protection == | 2032 | conn_state->content_protection == |
| @@ -2101,6 +2101,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, | |||
| 2101 | if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) | 2101 | if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) |
| 2102 | mhdp->info->ops->disable(mhdp); | 2102 | mhdp->info->ops->disable(mhdp); |
| 2103 | 2103 | ||
| 2104 | + mhdp->connector_ptr = NULL; | ||
| 2104 | mutex_unlock(&mhdp->link_mutex); | 2105 | mutex_unlock(&mhdp->link_mutex); |
| 2105 | } | 2106 | } |
| 2106 | 2107 | ||
| @@ -2366,7 +2367,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work) | |||
| 2366 | 2367 | ||
| 2367 | mhdp = container_of(work, typeof(*mhdp), modeset_retry_work); | 2368 | mhdp = container_of(work, typeof(*mhdp), modeset_retry_work); |
| 2368 | 2369 | ||
| 2369 | - conn = &mhdp->connector; | 2370 | + conn = mhdp->connector_ptr; |
| 2370 | 2371 | ||
| 2371 | /* Grab the locks before changing connector property */ | 2372 | /* Grab the locks before changing connector property */ |
| 2372 | mutex_lock(&conn->dev->mode_config.mutex); | 2373 | mutex_lock(&conn->dev->mode_config.mutex); |
| @@ -2443,7 +2444,7 @@ static void cdns_mhdp_hpd_work(struct work_struct *work) | |||
| 2443 | int ret; | 2444 | int ret; |
| 2444 | 2445 | ||
| 2445 | ret = cdns_mhdp_update_link_status(mhdp); | 2446 | ret = cdns_mhdp_update_link_status(mhdp); |
| 2446 | - if (mhdp->connector.dev) { | 2447 | + if (mhdp->connector_ptr) { |
| 2447 | if (ret < 0) | 2448 | if (ret < 0) |
| 2448 | schedule_work(&mhdp->modeset_retry_work); | 2449 | schedule_work(&mhdp->modeset_retry_work); |
| 2449 | else | 2450 | else |
| @@ -376,6 +376,7 @@ struct cdns_mhdp_device { | |||
| 376 | struct mutex link_mutex; | 376 | struct mutex link_mutex; |
| 377 | 377 | ||
| 378 | struct drm_connector connector; | 378 | struct drm_connector connector; |
| 379 | + struct drm_connector *connector_ptr; | ||
| 379 | struct drm_bridge bridge; | 380 | struct drm_bridge bridge; |
| 380 | 381 | ||
| 381 | struct cdns_mhdp_link link; | 382 | struct cdns_mhdp_link link; |
| @@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) | |||
| 394 | int ret; | 394 | int ret; |
| 395 | 395 | ||
| 396 | dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", | 396 | dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", |
| 397 | - mhdp->connector.name, mhdp->connector.base.id); | 397 | + mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); |
| 398 | 398 | ||
| 399 | ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); | 399 | ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); |
| 400 | 400 | ||
| @@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) | |||
| 436 | int ret = 0; | 436 | int ret = 0; |
| 437 | 437 | ||
| 438 | mutex_lock(&mhdp->hdcp.mutex); | 438 | mutex_lock(&mhdp->hdcp.mutex); |
| 439 | + | ||
| 440 | + if (!mhdp->connector_ptr) | ||
| 441 | + goto out; | ||
| 442 | + | ||
| 439 | if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) | 443 | if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) |
| 440 | goto out; | 444 | goto out; |
| 441 | 445 | ||
| @@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) | |||
| 445 | 449 | ||
| 446 | dev_err(mhdp->dev, | 450 | dev_err(mhdp->dev, |
| 447 | "[%s:%d] HDCP link failed, retrying authentication\n", | 451 | "[%s:%d] HDCP link failed, retrying authentication\n", |
| 448 | - mhdp->connector.name, mhdp->connector.base.id); | 452 | + mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); |
| 449 | 453 | ||
| 450 | ret = _cdns_mhdp_hdcp_disable(mhdp); | 454 | ret = _cdns_mhdp_hdcp_disable(mhdp); |
| 451 | if (ret) { | 455 | if (ret) { |
| @@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) | |||
| 487 | struct cdns_mhdp_device *mhdp = container_of(hdcp, | 491 | struct cdns_mhdp_device *mhdp = container_of(hdcp, |
| 488 | struct cdns_mhdp_device, | 492 | struct cdns_mhdp_device, |
| 489 | hdcp); | 493 | hdcp); |
| 490 | - struct drm_device *dev = mhdp->connector.dev; | 494 | + struct drm_device *dev = NULL; |
| 491 | struct drm_connector_state *state; | 495 | struct drm_connector_state *state; |
| 492 | 496 | ||
| 497 | + if (mhdp->connector_ptr) | ||
| 498 | + dev = mhdp->connector_ptr->dev; | ||
| 499 | + | ||
| 500 | + if (!dev) | ||
| 501 | + return; | ||
| 502 | + | ||
| 493 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | 503 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
| 494 | mutex_lock(&mhdp->hdcp.mutex); | 504 | mutex_lock(&mhdp->hdcp.mutex); |
| 495 | if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { | 505 | if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { |
| 496 | - state = mhdp->connector.state; | 506 | + state = mhdp->connector_ptr->state; |
| 497 | state->content_protection = mhdp->hdcp.value; | 507 | state->content_protection = mhdp->hdcp.value; |
| 498 | } | 508 | } |
| 499 | mutex_unlock(&mhdp->hdcp.mutex); | 509 | mutex_unlock(&mhdp->hdcp.mutex); |
| @@ -597,6 +597,9 @@ v3d_get_multisync_submit_deps(struct drm_file *file_priv, | |||
| 597 | if (multisync.pad) | 597 | if (multisync.pad) |
| 598 | return -EINVAL; | 598 | return -EINVAL; |
| 599 | 599 | ||
| 600 | + if (!multisync.in_sync_count && !multisync.out_sync_count) | ||
| 601 | + return -EINVAL; | ||
| 602 | + | ||
| 600 | ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count, | 603 | ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count, |
| 601 | multisync.out_syncs); | 604 | multisync.out_syncs); |
| 602 | if (ret) | 605 | if (ret) |
| @@ -118,7 +118,10 @@ static void virtio_gpu_remove(struct virtio_device *vdev) | |||
| 118 | struct drm_device *dev = vdev->priv; | 118 | struct drm_device *dev = vdev->priv; |
| 119 | 119 | ||
| 120 | drm_dev_unplug(dev); | 120 | drm_dev_unplug(dev); |
| 121 | - drm_atomic_helper_shutdown(dev); | 121 | + |
| 122 | + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) | ||
| 123 | + drm_atomic_helper_shutdown(dev); | ||
| 124 | + | ||
| 122 | virtio_gpu_deinit(dev); | 125 | virtio_gpu_deinit(dev); |
| 123 | drm_dev_put(dev); | 126 | drm_dev_put(dev); |
| 124 | } | 127 | } |
| @@ -349,7 +349,7 @@ static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff) | |||
| 349 | { | 349 | { |
| 350 | int record_count; | 350 | int record_count; |
| 351 | char index; | 351 | char index; |
| 352 | - u8 buf[5]; | 352 | + u8 buf[I2C_SMBUS_BLOCK_MAX]; |
| 353 | int ret; | 353 | int ret; |
| 354 | 354 | ||
| 355 | ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf); | 355 | ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf); |
| @@ -918,13 +918,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, | |||
| 918 | */ | 918 | */ |
| 919 | if (hwpec) | 919 | if (hwpec) |
| 920 | outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv)); | 920 | outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv)); |
| 921 | -out: | ||
| 922 | /* | 921 | /* |
| 923 | * Unlock the SMBus device for use by BIOS/ACPI, | 922 | * Unlock the SMBus device for use by BIOS/ACPI, |
| 924 | * and clear status flags if not done already. | 923 | * and clear status flags if not done already. |
| 925 | */ | 924 | */ |
| 926 | outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv)); | 925 | outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv)); |
| 927 | 926 | ||
| 927 | +out: | ||
| 928 | pm_runtime_mark_last_busy(&priv->pci_dev->dev); | 928 | pm_runtime_mark_last_busy(&priv->pci_dev->dev); |
| 929 | pm_runtime_put_autosuspend(&priv->pci_dev->dev); | 929 | pm_runtime_put_autosuspend(&priv->pci_dev->dev); |
| 930 | mutex_unlock(&priv->acpi_lock); | 930 | mutex_unlock(&priv->acpi_lock); |
| @@ -85,9 +85,9 @@ enum { | |||
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | enum { | 87 | enum { |
| 88 | - ADMV1013_SE_MODE_POS = 6, | 88 | + ADMV1013_SE_MODE_POS, |
| 89 | - ADMV1013_SE_MODE_NEG = 9, | 89 | + ADMV1013_SE_MODE_NEG, |
| 90 | - ADMV1013_SE_MODE_DIFF = 12 | 90 | + ADMV1013_SE_MODE_DIFF, |
| 91 | }; | 91 | }; |
| 92 | 92 | ||
| 93 | struct admv1013_state { | 93 | struct admv1013_state { |
| @@ -476,10 +476,23 @@ static int admv1013_init(struct admv1013_state *st) | |||
| 476 | if (ret) | 476 | if (ret) |
| 477 | return ret; | 477 | return ret; |
| 478 | 478 | ||
| 479 | - data = FIELD_PREP(ADMV1013_QUAD_SE_MODE_MSK, st->quad_se_mode); | 479 | + switch (st->quad_se_mode) { |
| 480 | + case ADMV1013_SE_MODE_POS: | ||
| 481 | + data = 6; | ||
| 482 | + break; | ||
| 483 | + case ADMV1013_SE_MODE_NEG: | ||
| 484 | + data = 9; | ||
| 485 | + break; | ||
| 486 | + case ADMV1013_SE_MODE_DIFF: | ||
| 487 | + data = 12; | ||
| 488 | + break; | ||
| 489 | + default: | ||
| 490 | + return -EINVAL; | ||
| 491 | + } | ||
| 480 | 492 | ||
| 481 | ret = __admv1013_spi_update_bits(st, ADMV1013_REG_QUAD, | 493 | ret = __admv1013_spi_update_bits(st, ADMV1013_REG_QUAD, |
| 482 | - ADMV1013_QUAD_SE_MODE_MSK, data); | 494 | + ADMV1013_QUAD_SE_MODE_MSK, |
| 495 | + FIELD_PREP(ADMV1013_QUAD_SE_MODE_MSK, data)); | ||
| 483 | if (ret) | 496 | if (ret) |
| 484 | return ret; | 497 | return ret; |
| 485 | 498 | ||
| @@ -534,28 +547,30 @@ static int admv1013_properties_parse(struct admv1013_state *st) | |||
| 534 | st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable"); | 547 | st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable"); |
| 535 | 548 | ||
| 536 | ret = device_property_read_string(&spi->dev, "adi,input-mode", &str); | 549 | ret = device_property_read_string(&spi->dev, "adi,input-mode", &str); |
| 537 | - if (ret) | 550 | + if (!ret) { |
| 551 | + if (!strcmp(str, "iq")) | ||
| 552 | + st->input_mode = ADMV1013_IQ_MODE; | ||
| 553 | + else if (!strcmp(str, "if")) | ||
| 554 | + st->input_mode = ADMV1013_IF_MODE; | ||
| 555 | + else | ||
| 556 | + return -EINVAL; | ||
| 557 | + } else { | ||
| 538 | st->input_mode = ADMV1013_IQ_MODE; | 558 | st->input_mode = ADMV1013_IQ_MODE; |
| 539 | - | 559 | + } |
| 540 | - if (!strcmp(str, "iq")) | ||
| 541 | - st->input_mode = ADMV1013_IQ_MODE; | ||
| 542 | - else if (!strcmp(str, "if")) | ||
| 543 | - st->input_mode = ADMV1013_IF_MODE; | ||
| 544 | - else | ||
| 545 | - return -EINVAL; | ||
| 546 | 560 | ||
| 547 | ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str); | 561 | ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str); |
| 548 | - if (ret) | 562 | + if (!ret) { |
| 563 | + if (!strcmp(str, "diff")) | ||
| 564 | + st->quad_se_mode = ADMV1013_SE_MODE_DIFF; | ||
| 565 | + else if (!strcmp(str, "se-pos")) | ||
| 566 | + st->quad_se_mode = ADMV1013_SE_MODE_POS; | ||
| 567 | + else if (!strcmp(str, "se-neg")) | ||
| 568 | + st->quad_se_mode = ADMV1013_SE_MODE_NEG; | ||
| 569 | + else | ||
| 570 | + return -EINVAL; | ||
| 571 | + } else { | ||
| 549 | st->quad_se_mode = ADMV1013_SE_MODE_DIFF; | 572 | st->quad_se_mode = ADMV1013_SE_MODE_DIFF; |
| 550 | - | 573 | + } |
| 551 | - if (!strcmp(str, "diff")) | ||
| 552 | - st->quad_se_mode = ADMV1013_SE_MODE_DIFF; | ||
| 553 | - else if (!strcmp(str, "se-pos")) | ||
| 554 | - st->quad_se_mode = ADMV1013_SE_MODE_POS; | ||
| 555 | - else if (!strcmp(str, "se-neg")) | ||
| 556 | - st->quad_se_mode = ADMV1013_SE_MODE_NEG; | ||
| 557 | - else | ||
| 558 | - return -EINVAL; | ||
| 559 | 574 | ||
| 560 | st->reg = devm_regulator_get(&spi->dev, "vcm"); | 575 | st->reg = devm_regulator_get(&spi->dev, "vcm"); |
| 561 | if (IS_ERR(st->reg)) | 576 | if (IS_ERR(st->reg)) |
| @@ -72,14 +72,46 @@ void rxe_mr_init_dma(int access, struct rxe_mr *mr) | |||
| 72 | mr->ibmr.type = IB_MR_TYPE_DMA; | 72 | mr->ibmr.type = IB_MR_TYPE_DMA; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | +/* | ||
| 76 | + * Convert iova to page_info index. The page_info stores pages of size | ||
| 77 | + * PAGE_SIZE, but MRs can have different page sizes. This function | ||
| 78 | + * handles the conversion for all cases: | ||
| 79 | + * | ||
| 80 | + * 1. mr->page_size > PAGE_SIZE: | ||
| 81 | + * The MR's iova may not be aligned to mr->page_size. We use the | ||
| 82 | + * aligned base (iova & page_mask) as reference, then calculate | ||
| 83 | + * which PAGE_SIZE sub-page the iova falls into. | ||
| 84 | + * | ||
| 85 | + * 2. mr->page_size <= PAGE_SIZE: | ||
| 86 | + * Use simple shift arithmetic since each page_info entry corresponds | ||
| 87 | + * to one or more MR pages. | ||
| 88 | + */ | ||
| 75 | static unsigned long rxe_mr_iova_to_index(struct rxe_mr *mr, u64 iova) | 89 | static unsigned long rxe_mr_iova_to_index(struct rxe_mr *mr, u64 iova) |
| 76 | { | 90 | { |
| 77 | - return (iova >> mr->page_shift) - (mr->ibmr.iova >> mr->page_shift); | 91 | + int idx; |
| 92 | + | ||
| 93 | + if (mr_page_size(mr) > PAGE_SIZE) | ||
| 94 | + idx = (iova - (mr->ibmr.iova & mr->page_mask)) >> PAGE_SHIFT; | ||
| 95 | + else | ||
| 96 | + idx = (iova >> mr->page_shift) - | ||
| 97 | + (mr->ibmr.iova >> mr->page_shift); | ||
| 98 | + | ||
| 99 | + WARN_ON(idx >= mr->nbuf); | ||
| 100 | + return idx; | ||
| 78 | } | 101 | } |
| 79 | 102 | ||
| 103 | +/* | ||
| 104 | + * Convert iova to offset within the page_info entry. | ||
| 105 | + * | ||
| 106 | + * For mr_page_size > PAGE_SIZE, the offset is within the system page. | ||
| 107 | + * For mr_page_size <= PAGE_SIZE, the offset is within the MR page size. | ||
| 108 | + */ | ||
| 80 | static unsigned long rxe_mr_iova_to_page_offset(struct rxe_mr *mr, u64 iova) | 109 | static unsigned long rxe_mr_iova_to_page_offset(struct rxe_mr *mr, u64 iova) |
| 81 | { | 110 | { |
| 82 | - return iova & (mr_page_size(mr) - 1); | 111 | + if (mr_page_size(mr) > PAGE_SIZE) |
| 112 | + return iova & (PAGE_SIZE - 1); | ||
| 113 | + else | ||
| 114 | + return iova & (mr_page_size(mr) - 1); | ||
| 83 | } | 115 | } |
| 84 | 116 | ||
| 85 | static bool is_pmem_page(struct page *pg) | 117 | static bool is_pmem_page(struct page *pg) |
| @@ -93,37 +125,69 @@ static bool is_pmem_page(struct page *pg) | |||
| 93 | 125 | ||
| 94 | static int rxe_mr_fill_pages_from_sgt(struct rxe_mr *mr, struct sg_table *sgt) | 126 | static int rxe_mr_fill_pages_from_sgt(struct rxe_mr *mr, struct sg_table *sgt) |
| 95 | { | 127 | { |
| 96 | - XA_STATE(xas, &mr->page_list, 0); | ||
| 97 | struct sg_page_iter sg_iter; | 128 | struct sg_page_iter sg_iter; |
| 98 | struct page *page; | 129 | struct page *page; |
| 99 | bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); | 130 | bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); |
| 100 | 131 | ||
| 132 | + WARN_ON(mr_page_size(mr) != PAGE_SIZE); | ||
| 133 | + | ||
| 101 | __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0); | 134 | __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0); |
| 102 | if (!__sg_page_iter_next(&sg_iter)) | 135 | if (!__sg_page_iter_next(&sg_iter)) |
| 103 | return 0; | 136 | return 0; |
| 104 | 137 | ||
| 105 | - do { | 138 | + while (true) { |
| 106 | - xas_lock(&xas); | 139 | + page = sg_page_iter_page(&sg_iter); |
| 107 | - while (true) { | ||
| 108 | - page = sg_page_iter_page(&sg_iter); | ||
| 109 | 140 | ||
| 110 | - if (persistent && !is_pmem_page(page)) { | 141 | + if (persistent && !is_pmem_page(page)) { |
| 111 | - rxe_dbg_mr(mr, "Page can't be persistent\n"); | 142 | + rxe_dbg_mr(mr, "Page can't be persistent\n"); |
| 112 | - xas_set_err(&xas, -EINVAL); | 143 | + return -EINVAL; |
| 113 | - break; | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - xas_store(&xas, page); | ||
| 117 | - if (xas_error(&xas)) | ||
| 118 | - break; | ||
| 119 | - xas_next(&xas); | ||
| 120 | - if (!__sg_page_iter_next(&sg_iter)) | ||
| 121 | - break; | ||
| 122 | } | 144 | } |
| 123 | - xas_unlock(&xas); | ||
| 124 | - } while (xas_nomem(&xas, GFP_KERNEL)); | ||
| 125 | 145 | ||
| 126 | - return xas_error(&xas); | 146 | + mr->page_info[mr->nbuf].page = page; |
| 147 | + mr->page_info[mr->nbuf].offset = 0; | ||
| 148 | + mr->nbuf++; | ||
| 149 | + | ||
| 150 | + if (!__sg_page_iter_next(&sg_iter)) | ||
| 151 | + break; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + return 0; | ||
| 155 | +} | ||
| 156 | + | ||
| 157 | +static int __alloc_mr_page_info(struct rxe_mr *mr, int num_pages) | ||
| 158 | +{ | ||
| 159 | + mr->page_info = kcalloc(num_pages, sizeof(struct rxe_mr_page), | ||
| 160 | + GFP_KERNEL); | ||
| 161 | + if (!mr->page_info) | ||
| 162 | + return -ENOMEM; | ||
| 163 | + | ||
| 164 | + mr->max_allowed_buf = num_pages; | ||
| 165 | + mr->nbuf = 0; | ||
| 166 | + | ||
| 167 | + return 0; | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +static int alloc_mr_page_info(struct rxe_mr *mr, int num_pages) | ||
| 171 | +{ | ||
| 172 | + int ret; | ||
| 173 | + | ||
| 174 | + WARN_ON(mr->num_buf); | ||
| 175 | + ret = __alloc_mr_page_info(mr, num_pages); | ||
| 176 | + if (ret) | ||
| 177 | + return ret; | ||
| 178 | + | ||
| 179 | + mr->num_buf = num_pages; | ||
| 180 | + | ||
| 181 | + return 0; | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +static void free_mr_page_info(struct rxe_mr *mr) | ||
| 185 | +{ | ||
| 186 | + if (!mr->page_info) | ||
| 187 | + return; | ||
| 188 | + | ||
| 189 | + kfree(mr->page_info); | ||
| 190 | + mr->page_info = NULL; | ||
| 127 | } | 191 | } |
| 128 | 192 | ||
| 129 | int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova, | 193 | int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova, |
| @@ -134,8 +198,6 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova, | |||
| 134 | 198 | ||
| 135 | rxe_mr_init(access, mr); | 199 | rxe_mr_init(access, mr); |
| 136 | 200 | ||
| 137 | - xa_init(&mr->page_list); | ||
| 138 | - | ||
| 139 | umem = ib_umem_get(&rxe->ib_dev, start, length, access); | 201 | umem = ib_umem_get(&rxe->ib_dev, start, length, access); |
| 140 | if (IS_ERR(umem)) { | 202 | if (IS_ERR(umem)) { |
| 141 | rxe_dbg_mr(mr, "Unable to pin memory region err = %d\n", | 203 | rxe_dbg_mr(mr, "Unable to pin memory region err = %d\n", |
| @@ -143,46 +205,24 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova, | |||
| 143 | return PTR_ERR(umem); | 205 | return PTR_ERR(umem); |
| 144 | } | 206 | } |
| 145 | 207 | ||
| 208 | + err = alloc_mr_page_info(mr, ib_umem_num_pages(umem)); | ||
| 209 | + if (err) | ||
| 210 | + goto err2; | ||
| 211 | + | ||
| 146 | err = rxe_mr_fill_pages_from_sgt(mr, &umem->sgt_append.sgt); | 212 | err = rxe_mr_fill_pages_from_sgt(mr, &umem->sgt_append.sgt); |
| 147 | - if (err) { | 213 | + if (err) |
| 148 | - ib_umem_release(umem); | 214 | + goto err1; |
| 149 | - return err; | ||
| 150 | - } | ||
| 151 | 215 | ||
| 152 | mr->umem = umem; | 216 | mr->umem = umem; |
| 153 | mr->ibmr.type = IB_MR_TYPE_USER; | 217 | mr->ibmr.type = IB_MR_TYPE_USER; |
| 154 | mr->state = RXE_MR_STATE_VALID; | 218 | mr->state = RXE_MR_STATE_VALID; |
| 155 | 219 | ||
| 156 | return 0; | 220 | return 0; |
| 157 | -} | 221 | +err1: |
| 158 | - | 222 | + free_mr_page_info(mr); |
| 159 | -static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf) | 223 | +err2: |
| 160 | -{ | 224 | + ib_umem_release(umem); |
| 161 | - XA_STATE(xas, &mr->page_list, 0); | 225 | + return err; |
| 162 | - int i = 0; | ||
| 163 | - int err; | ||
| 164 | - | ||
| 165 | - xa_init(&mr->page_list); | ||
| 166 | - | ||
| 167 | - do { | ||
| 168 | - xas_lock(&xas); | ||
| 169 | - while (i != num_buf) { | ||
| 170 | - xas_store(&xas, XA_ZERO_ENTRY); | ||
| 171 | - if (xas_error(&xas)) | ||
| 172 | - break; | ||
| 173 | - xas_next(&xas); | ||
| 174 | - i++; | ||
| 175 | - } | ||
| 176 | - xas_unlock(&xas); | ||
| 177 | - } while (xas_nomem(&xas, GFP_KERNEL)); | ||
| 178 | - | ||
| 179 | - err = xas_error(&xas); | ||
| 180 | - if (err) | ||
| 181 | - return err; | ||
| 182 | - | ||
| 183 | - mr->num_buf = num_buf; | ||
| 184 | - | ||
| 185 | - return 0; | ||
| 186 | } | 226 | } |
| 187 | 227 | ||
| 188 | int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) | 228 | int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) |
| @@ -192,7 +232,7 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) | |||
| 192 | /* always allow remote access for FMRs */ | 232 | /* always allow remote access for FMRs */ |
| 193 | rxe_mr_init(RXE_ACCESS_REMOTE, mr); | 233 | rxe_mr_init(RXE_ACCESS_REMOTE, mr); |
| 194 | 234 | ||
| 195 | - err = rxe_mr_alloc(mr, max_pages); | 235 | + err = alloc_mr_page_info(mr, max_pages); |
| 196 | if (err) | 236 | if (err) |
| 197 | goto err1; | 237 | goto err1; |
| 198 | 238 | ||
| @@ -205,26 +245,43 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) | |||
| 205 | return err; | 245 | return err; |
| 206 | } | 246 | } |
| 207 | 247 | ||
| 248 | +/* | ||
| 249 | + * I) MRs with page_size >= PAGE_SIZE, | ||
| 250 | + * Split a large MR page (mr->page_size) into multiple PAGE_SIZE | ||
| 251 | + * sub-pages and store them in page_info, offset is always 0. | ||
| 252 | + * | ||
| 253 | + * Called when mr->page_size > PAGE_SIZE. Each call to rxe_set_page() | ||
| 254 | + * represents one mr->page_size region, which we must split into | ||
| 255 | + * (mr->page_size >> PAGE_SHIFT) individual pages. | ||
| 256 | + * | ||
| 257 | + * II) MRs with page_size < PAGE_SIZE, | ||
| 258 | + * Save each PAGE_SIZE page and its offset within the system page in page_info. | ||
| 259 | + */ | ||
| 208 | static int rxe_set_page(struct ib_mr *ibmr, u64 dma_addr) | 260 | static int rxe_set_page(struct ib_mr *ibmr, u64 dma_addr) |
| 209 | { | 261 | { |
| 210 | struct rxe_mr *mr = to_rmr(ibmr); | 262 | struct rxe_mr *mr = to_rmr(ibmr); |
| 211 | - struct page *page = ib_virt_dma_to_page(dma_addr); | ||
| 212 | bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); | 263 | bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); |
| 213 | - int err; | 264 | + u32 i, pages_per_mr = mr_page_size(mr) >> PAGE_SHIFT; |
| 214 | 265 | ||
| 215 | - if (persistent && !is_pmem_page(page)) { | 266 | + pages_per_mr = MAX(1, pages_per_mr); |
| 216 | - rxe_dbg_mr(mr, "Page cannot be persistent\n"); | 267 | + |
| 217 | - return -EINVAL; | 268 | + for (i = 0; i < pages_per_mr; i++) { |
| 269 | + u64 addr = dma_addr + i * PAGE_SIZE; | ||
| 270 | + struct page *sub_page = ib_virt_dma_to_page(addr); | ||
| 271 | + | ||
| 272 | + if (unlikely(mr->nbuf >= mr->max_allowed_buf)) | ||
| 273 | + return -ENOMEM; | ||
| 274 | + | ||
| 275 | + if (persistent && !is_pmem_page(sub_page)) { | ||
| 276 | + rxe_dbg_mr(mr, "Page cannot be persistent\n"); | ||
| 277 | + return -EINVAL; | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + mr->page_info[mr->nbuf].page = sub_page; | ||
| 281 | + mr->page_info[mr->nbuf].offset = addr & (PAGE_SIZE - 1); | ||
| 282 | + mr->nbuf++; | ||
| 218 | } | 283 | } |
| 219 | 284 | ||
| 220 | - if (unlikely(mr->nbuf == mr->num_buf)) | ||
| 221 | - return -ENOMEM; | ||
| 222 | - | ||
| 223 | - err = xa_err(xa_store(&mr->page_list, mr->nbuf, page, GFP_KERNEL)); | ||
| 224 | - if (err) | ||
| 225 | - return err; | ||
| 226 | - | ||
| 227 | - mr->nbuf++; | ||
| 228 | return 0; | 285 | return 0; |
| 229 | } | 286 | } |
| 230 | 287 | ||
| @@ -234,6 +291,31 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl, | |||
| 234 | struct rxe_mr *mr = to_rmr(ibmr); | 291 | struct rxe_mr *mr = to_rmr(ibmr); |
| 235 | unsigned int page_size = mr_page_size(mr); | 292 | unsigned int page_size = mr_page_size(mr); |
| 236 | 293 | ||
| 294 | + /* | ||
| 295 | + * Ensure page_size and PAGE_SIZE are compatible for mapping. | ||
| 296 | + * We require one to be a multiple of the other for correct | ||
| 297 | + * iova-to-page conversion. | ||
| 298 | + */ | ||
| 299 | + if (!IS_ALIGNED(page_size, PAGE_SIZE) && | ||
| 300 | + !IS_ALIGNED(PAGE_SIZE, page_size)) { | ||
| 301 | + rxe_dbg_mr(mr, "MR page size %u must be compatible with PAGE_SIZE %lu\n", | ||
| 302 | + page_size, PAGE_SIZE); | ||
| 303 | + return -EINVAL; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + if (mr_page_size(mr) > PAGE_SIZE) { | ||
| 307 | + /* resize page_info if needed */ | ||
| 308 | + u32 map_mr_pages = (page_size >> PAGE_SHIFT) * mr->num_buf; | ||
| 309 | + | ||
| 310 | + if (map_mr_pages > mr->max_allowed_buf) { | ||
| 311 | + rxe_dbg_mr(mr, "requested pages %u exceed max %u\n", | ||
| 312 | + map_mr_pages, mr->max_allowed_buf); | ||
| 313 | + free_mr_page_info(mr); | ||
| 314 | + if (__alloc_mr_page_info(mr, map_mr_pages)) | ||
| 315 | + return -ENOMEM; | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + | ||
| 237 | mr->nbuf = 0; | 319 | mr->nbuf = 0; |
| 238 | mr->page_shift = ilog2(page_size); | 320 | mr->page_shift = ilog2(page_size); |
| 239 | mr->page_mask = ~((u64)page_size - 1); | 321 | mr->page_mask = ~((u64)page_size - 1); |
| @@ -245,30 +327,30 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl, | |||
| 245 | static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr, | 327 | static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr, |
| 246 | unsigned int length, enum rxe_mr_copy_dir dir) | 328 | unsigned int length, enum rxe_mr_copy_dir dir) |
| 247 | { | 329 | { |
| 248 | - unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); | ||
| 249 | - unsigned long index = rxe_mr_iova_to_index(mr, iova); | ||
| 250 | unsigned int bytes; | 330 | unsigned int bytes; |
| 251 | - struct page *page; | 331 | + u8 *va; |
| 252 | - void *va; | ||
| 253 | 332 | ||
| 254 | while (length) { | 333 | while (length) { |
| 255 | - page = xa_load(&mr->page_list, index); | 334 | + unsigned long index = rxe_mr_iova_to_index(mr, iova); |
| 256 | - if (!page) | 335 | + struct rxe_mr_page *info = &mr->page_info[index]; |
| 336 | + unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); | ||
| 337 | + | ||
| 338 | + if (!info->page) | ||
| 257 | return -EFAULT; | 339 | return -EFAULT; |
| 258 | 340 | ||
| 259 | - bytes = min_t(unsigned int, length, | 341 | + page_offset += info->offset; |
| 260 | - mr_page_size(mr) - page_offset); | 342 | + bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); |
| 261 | - va = kmap_local_page(page); | 343 | + va = kmap_local_page(info->page); |
| 344 | + | ||
| 262 | if (dir == RXE_FROM_MR_OBJ) | 345 | if (dir == RXE_FROM_MR_OBJ) |
| 263 | memcpy(addr, va + page_offset, bytes); | 346 | memcpy(addr, va + page_offset, bytes); |
| 264 | else | 347 | else |
| 265 | memcpy(va + page_offset, addr, bytes); | 348 | memcpy(va + page_offset, addr, bytes); |
| 266 | kunmap_local(va); | 349 | kunmap_local(va); |
| 267 | 350 | ||
| 268 | - page_offset = 0; | ||
| 269 | addr += bytes; | 351 | addr += bytes; |
| 352 | + iova += bytes; | ||
| 270 | length -= bytes; | 353 | length -= bytes; |
| 271 | - index++; | ||
| 272 | } | 354 | } |
| 273 | 355 | ||
| 274 | return 0; | 356 | return 0; |
| @@ -423,9 +505,6 @@ int copy_data( | |||
| 423 | 505 | ||
| 424 | int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length) | 506 | int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length) |
| 425 | { | 507 | { |
| 426 | - unsigned int page_offset; | ||
| 427 | - unsigned long index; | ||
| 428 | - struct page *page; | ||
| 429 | unsigned int bytes; | 508 | unsigned int bytes; |
| 430 | int err; | 509 | int err; |
| 431 | u8 *va; | 510 | u8 *va; |
| @@ -445,15 +524,16 @@ int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length) | |||
| 445 | return err; | 524 | return err; |
| 446 | 525 | ||
| 447 | while (length > 0) { | 526 | while (length > 0) { |
| 448 | - index = rxe_mr_iova_to_index(mr, iova); | 527 | + unsigned long index = rxe_mr_iova_to_index(mr, iova); |
| 449 | - page = xa_load(&mr->page_list, index); | 528 | + struct rxe_mr_page *info = &mr->page_info[index]; |
| 450 | - page_offset = rxe_mr_iova_to_page_offset(mr, iova); | 529 | + unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); |
| 451 | - if (!page) | ||
| 452 | - return -EFAULT; | ||
| 453 | - bytes = min_t(unsigned int, length, | ||
| 454 | - mr_page_size(mr) - page_offset); | ||
| 455 | 530 | ||
| 456 | - va = kmap_local_page(page); | 531 | + if (!info->page) |
| 532 | + return -EFAULT; | ||
| 533 | + page_offset += info->offset; | ||
| 534 | + bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); | ||
| 535 | + | ||
| 536 | + va = kmap_local_page(info->page); | ||
| 457 | arch_wb_cache_pmem(va + page_offset, bytes); | 537 | arch_wb_cache_pmem(va + page_offset, bytes); |
| 458 | kunmap_local(va); | 538 | kunmap_local(va); |
| 459 | 539 | ||
| @@ -487,6 +567,7 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, | |||
| 487 | } else { | 567 | } else { |
| 488 | unsigned long index; | 568 | unsigned long index; |
| 489 | int err; | 569 | int err; |
| 570 | + struct rxe_mr_page *info; | ||
| 490 | 571 | ||
| 491 | err = mr_check_range(mr, iova, sizeof(value)); | 572 | err = mr_check_range(mr, iova, sizeof(value)); |
| 492 | if (err) { | 573 | if (err) { |
| @@ -495,9 +576,12 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, | |||
| 495 | } | 576 | } |
| 496 | page_offset = rxe_mr_iova_to_page_offset(mr, iova); | 577 | page_offset = rxe_mr_iova_to_page_offset(mr, iova); |
| 497 | index = rxe_mr_iova_to_index(mr, iova); | 578 | index = rxe_mr_iova_to_index(mr, iova); |
| 498 | - page = xa_load(&mr->page_list, index); | 579 | + info = &mr->page_info[index]; |
| 499 | - if (!page) | 580 | + if (!info->page) |
| 500 | return RESPST_ERR_RKEY_VIOLATION; | 581 | return RESPST_ERR_RKEY_VIOLATION; |
| 582 | + | ||
| 583 | + page_offset += info->offset; | ||
| 584 | + page = info->page; | ||
| 501 | } | 585 | } |
| 502 | 586 | ||
| 503 | if (unlikely(page_offset & 0x7)) { | 587 | if (unlikely(page_offset & 0x7)) { |
| @@ -544,6 +628,7 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) | |||
| 544 | } else { | 628 | } else { |
| 545 | unsigned long index; | 629 | unsigned long index; |
| 546 | int err; | 630 | int err; |
| 631 | + struct rxe_mr_page *info; | ||
| 547 | 632 | ||
| 548 | /* See IBA oA19-28 */ | 633 | /* See IBA oA19-28 */ |
| 549 | err = mr_check_range(mr, iova, sizeof(value)); | 634 | err = mr_check_range(mr, iova, sizeof(value)); |
| @@ -553,9 +638,12 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) | |||
| 553 | } | 638 | } |
| 554 | page_offset = rxe_mr_iova_to_page_offset(mr, iova); | 639 | page_offset = rxe_mr_iova_to_page_offset(mr, iova); |
| 555 | index = rxe_mr_iova_to_index(mr, iova); | 640 | index = rxe_mr_iova_to_index(mr, iova); |
| 556 | - page = xa_load(&mr->page_list, index); | 641 | + info = &mr->page_info[index]; |
| 557 | - if (!page) | 642 | + if (!info->page) |
| 558 | return RESPST_ERR_RKEY_VIOLATION; | 643 | return RESPST_ERR_RKEY_VIOLATION; |
| 644 | + | ||
| 645 | + page_offset += info->offset; | ||
| 646 | + page = info->page; | ||
| 559 | } | 647 | } |
| 560 | 648 | ||
| 561 | /* See IBA A19.4.2 */ | 649 | /* See IBA A19.4.2 */ |
| @@ -727,5 +815,5 @@ void rxe_mr_cleanup(struct rxe_pool_elem *elem) | |||
| 727 | ib_umem_release(mr->umem); | 815 | ib_umem_release(mr->umem); |
| 728 | 816 | ||
| 729 | if (mr->ibmr.type != IB_MR_TYPE_DMA) | 817 | if (mr->ibmr.type != IB_MR_TYPE_DMA) |
| 730 | - xa_destroy(&mr->page_list); | 818 | + free_mr_page_info(mr); |
| 731 | } | 819 | } |
| @@ -297,6 +297,11 @@ static inline int rkey_is_mw(u32 rkey) | |||
| 297 | return (index >= RXE_MIN_MW_INDEX) && (index <= RXE_MAX_MW_INDEX); | 297 | return (index >= RXE_MIN_MW_INDEX) && (index <= RXE_MAX_MW_INDEX); |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | +struct rxe_mr_page { | ||
| 301 | + struct page *page; | ||
| 302 | + unsigned int offset; /* offset in system page */ | ||
| 303 | +}; | ||
| 304 | + | ||
| 300 | struct rxe_mr { | 305 | struct rxe_mr { |
| 301 | struct rxe_pool_elem elem; | 306 | struct rxe_pool_elem elem; |
| 302 | struct ib_mr ibmr; | 307 | struct ib_mr ibmr; |
| @@ -313,10 +318,13 @@ struct rxe_mr { | |||
| 313 | unsigned int page_shift; | 318 | unsigned int page_shift; |
| 314 | u64 page_mask; | 319 | u64 page_mask; |
| 315 | 320 | ||
| 321 | + /* size of page_info when mr allocated */ | ||
| 316 | u32 num_buf; | 322 | u32 num_buf; |
| 323 | + /* real size of page_info */ | ||
| 324 | + u32 max_allowed_buf; | ||
| 317 | u32 nbuf; | 325 | u32 nbuf; |
| 318 | 326 | ||
| 319 | - struct xarray page_list; | 327 | + struct rxe_mr_page *page_info; |
| 320 | }; | 328 | }; |
| 321 | 329 | ||
| 322 | static inline unsigned int mr_page_size(struct rxe_mr *mr) | 330 | static inline unsigned int mr_page_size(struct rxe_mr *mr) |
| @@ -1041,7 +1041,12 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, | |||
| 1041 | return ret; | 1041 | return ret; |
| 1042 | 1042 | ||
| 1043 | if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { | 1043 | if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { |
| 1044 | - refclk = lpg_clk_rates_hi_res[FIELD_GET(PWM_CLK_SELECT_HI_RES_MASK, val)]; | 1044 | + unsigned int clk_idx = FIELD_GET(PWM_CLK_SELECT_HI_RES_MASK, val); |
| 1045 | + | ||
| 1046 | + if (clk_idx >= ARRAY_SIZE(lpg_clk_rates_hi_res)) | ||
| 1047 | + return -EINVAL; | ||
| 1048 | + | ||
| 1049 | + refclk = lpg_clk_rates_hi_res[clk_idx]; | ||
| 1045 | resolution = lpg_pwm_resolution_hi_res[FIELD_GET(PWM_SIZE_HI_RES_MASK, val)]; | 1050 | resolution = lpg_pwm_resolution_hi_res[FIELD_GET(PWM_SIZE_HI_RES_MASK, val)]; |
| 1046 | } else { | 1051 | } else { |
| 1047 | refclk = lpg_clk_rates[FIELD_GET(PWM_CLK_SELECT_MASK, val)]; | 1052 | refclk = lpg_clk_rates[FIELD_GET(PWM_CLK_SELECT_MASK, val)]; |
| @@ -2459,8 +2459,10 @@ static int tun_xdp_one(struct tun_struct *tun, | |||
| 2459 | bool skb_xdp = false; | 2459 | bool skb_xdp = false; |
| 2460 | struct page *page; | 2460 | struct page *page; |
| 2461 | 2461 | ||
| 2462 | - if (unlikely(datasize < ETH_HLEN)) | 2462 | + if (unlikely(datasize < ETH_HLEN)) { |
| 2463 | + put_page(virt_to_head_page(xdp->data)); | ||
| 2463 | return -EINVAL; | 2464 | return -EINVAL; |
| 2465 | + } | ||
| 2464 | 2466 | ||
| 2465 | xdp_prog = rcu_dereference(tun->xdp_prog); | 2467 | xdp_prog = rcu_dereference(tun->xdp_prog); |
| 2466 | if (xdp_prog) { | 2468 | if (xdp_prog) { |
| @@ -2126,6 +2126,11 @@ static int __init epf_ntb_init(void) | |||
| 2126 | 2126 | ||
| 2127 | kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | | 2127 | kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | |
| 2128 | WQ_HIGHPRI, 0); | 2128 | WQ_HIGHPRI, 0); |
| 2129 | + if (!kpcintb_workqueue) { | ||
| 2130 | + pr_err("Failed to allocate kpcintb workqueue\n"); | ||
| 2131 | + return -ENOMEM; | ||
| 2132 | + } | ||
| 2133 | + | ||
| 2129 | ret = pci_epf_register_driver(&epf_ntb_driver); | 2134 | ret = pci_epf_register_driver(&epf_ntb_driver); |
| 2130 | if (ret) { | 2135 | if (ret) { |
| 2131 | destroy_workqueue(kpcintb_workqueue); | 2136 | destroy_workqueue(kpcintb_workqueue); |
| @@ -1450,6 +1450,11 @@ static int __init epf_ntb_init(void) | |||
| 1450 | 1450 | ||
| 1451 | kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | | 1451 | kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | |
| 1452 | WQ_HIGHPRI, 0); | 1452 | WQ_HIGHPRI, 0); |
| 1453 | + if (!kpcintb_workqueue) { | ||
| 1454 | + pr_err("Failed to allocate kpcintb workqueue\n"); | ||
| 1455 | + return -ENOMEM; | ||
| 1456 | + } | ||
| 1457 | + | ||
| 1453 | ret = pci_epf_register_driver(&epf_ntb_driver); | 1458 | ret = pci_epf_register_driver(&epf_ntb_driver); |
| 1454 | if (ret) { | 1459 | if (ret) { |
| 1455 | destroy_workqueue(kpcintb_workqueue); | 1460 | destroy_workqueue(kpcintb_workqueue); |
| @@ -747,6 +747,37 @@ fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats) | |||
| 747 | } | 747 | } |
| 748 | } | 748 | } |
| 749 | 749 | ||
| 750 | +static void | ||
| 751 | +fc_fpin_pname_stats_update(struct Scsi_Host *shost, | ||
| 752 | + struct fc_rport *attach_rport, u16 event_type, | ||
| 753 | + u32 desc_len, u32 fixed_len, u32 pname_count, | ||
| 754 | + __be64 *pname_list, | ||
| 755 | + void (*stats_update)(u16 event_type, | ||
| 756 | + struct fc_fpin_stats *stats)) | ||
| 757 | +{ | ||
| 758 | + u32 i; | ||
| 759 | + struct fc_rport *rport; | ||
| 760 | + u64 wwpn; | ||
| 761 | + | ||
| 762 | + if (desc_len < fixed_len) | ||
| 763 | + pname_count = 0; | ||
| 764 | + else | ||
| 765 | + pname_count = min(pname_count, (desc_len - fixed_len) / | ||
| 766 | + sizeof(pname_list[0])); | ||
| 767 | + | ||
| 768 | + for (i = 0; i < pname_count; i++) { | ||
| 769 | + wwpn = be64_to_cpu(pname_list[i]); | ||
| 770 | + rport = fc_find_rport_by_wwpn(shost, wwpn); | ||
| 771 | + if (rport && | ||
| 772 | + (rport->roles & FC_PORT_ROLE_FCP_TARGET || | ||
| 773 | + rport->roles & FC_PORT_ROLE_NVME_TARGET)) { | ||
| 774 | + if (rport == attach_rport) | ||
| 775 | + continue; | ||
| 776 | + stats_update(event_type, &rport->fpin_stats); | ||
| 777 | + } | ||
| 778 | + } | ||
| 779 | +} | ||
| 780 | + | ||
| 750 | /* | 781 | /* |
| 751 | * fc_fpin_li_stats_update - routine to update Link Integrity | 782 | * fc_fpin_li_stats_update - routine to update Link Integrity |
| 752 | * event statistics. | 783 | * event statistics. |
| @@ -757,13 +788,11 @@ fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats) | |||
| 757 | static void | 788 | static void |
| 758 | fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv) | 789 | fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv) |
| 759 | { | 790 | { |
| 760 | - u8 i; | ||
| 761 | struct fc_rport *rport = NULL; | 791 | struct fc_rport *rport = NULL; |
| 762 | struct fc_rport *attach_rport = NULL; | 792 | struct fc_rport *attach_rport = NULL; |
| 763 | struct fc_host_attrs *fc_host = shost_to_fc_host(shost); | 793 | struct fc_host_attrs *fc_host = shost_to_fc_host(shost); |
| 764 | struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv; | 794 | struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv; |
| 765 | u16 event_type = be16_to_cpu(li_desc->event_type); | 795 | u16 event_type = be16_to_cpu(li_desc->event_type); |
| 766 | - u64 wwpn; | ||
| 767 | 796 | ||
| 768 | rport = fc_find_rport_by_wwpn(shost, | 797 | rport = fc_find_rport_by_wwpn(shost, |
| 769 | be64_to_cpu(li_desc->attached_wwpn)); | 798 | be64_to_cpu(li_desc->attached_wwpn)); |
| @@ -774,22 +803,11 @@ fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv) | |||
| 774 | fc_li_stats_update(event_type, &attach_rport->fpin_stats); | 803 | fc_li_stats_update(event_type, &attach_rport->fpin_stats); |
| 775 | } | 804 | } |
| 776 | 805 | ||
| 777 | - if (be32_to_cpu(li_desc->pname_count) > 0) { | 806 | + fc_fpin_pname_stats_update(shost, attach_rport, event_type, |
| 778 | - for (i = 0; | 807 | + be32_to_cpu(li_desc->desc_len), |
| 779 | - i < be32_to_cpu(li_desc->pname_count); | 808 | + FC_TLV_DESC_LENGTH_FROM_SZ(*li_desc), |
| 780 | - i++) { | 809 | + be32_to_cpu(li_desc->pname_count), |
| 781 | - wwpn = be64_to_cpu(li_desc->pname_list[i]); | 810 | + li_desc->pname_list, fc_li_stats_update); |
| 782 | - rport = fc_find_rport_by_wwpn(shost, wwpn); | ||
| 783 | - if (rport && | ||
| 784 | - (rport->roles & FC_PORT_ROLE_FCP_TARGET || | ||
| 785 | - rport->roles & FC_PORT_ROLE_NVME_TARGET)) { | ||
| 786 | - if (rport == attach_rport) | ||
| 787 | - continue; | ||
| 788 | - fc_li_stats_update(event_type, | ||
| 789 | - &rport->fpin_stats); | ||
| 790 | - } | ||
| 791 | - } | ||
| 792 | - } | ||
| 793 | 811 | ||
| 794 | if (fc_host->port_name == be64_to_cpu(li_desc->attached_wwpn)) | 812 | if (fc_host->port_name == be64_to_cpu(li_desc->attached_wwpn)) |
| 795 | fc_li_stats_update(event_type, &fc_host->fpin_stats); | 813 | fc_li_stats_update(event_type, &fc_host->fpin_stats); |
| @@ -837,13 +855,11 @@ static void | |||
| 837 | fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost, | 855 | fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost, |
| 838 | struct fc_tlv_desc *tlv) | 856 | struct fc_tlv_desc *tlv) |
| 839 | { | 857 | { |
| 840 | - u8 i; | ||
| 841 | struct fc_rport *rport = NULL; | 858 | struct fc_rport *rport = NULL; |
| 842 | struct fc_rport *attach_rport = NULL; | 859 | struct fc_rport *attach_rport = NULL; |
| 843 | struct fc_fn_peer_congn_desc *pc_desc = | 860 | struct fc_fn_peer_congn_desc *pc_desc = |
| 844 | (struct fc_fn_peer_congn_desc *)tlv; | 861 | (struct fc_fn_peer_congn_desc *)tlv; |
| 845 | u16 event_type = be16_to_cpu(pc_desc->event_type); | 862 | u16 event_type = be16_to_cpu(pc_desc->event_type); |
| 846 | - u64 wwpn; | ||
| 847 | 863 | ||
| 848 | rport = fc_find_rport_by_wwpn(shost, | 864 | rport = fc_find_rport_by_wwpn(shost, |
| 849 | be64_to_cpu(pc_desc->attached_wwpn)); | 865 | be64_to_cpu(pc_desc->attached_wwpn)); |
| @@ -854,22 +870,11 @@ fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost, | |||
| 854 | fc_cn_stats_update(event_type, &attach_rport->fpin_stats); | 870 | fc_cn_stats_update(event_type, &attach_rport->fpin_stats); |
| 855 | } | 871 | } |
| 856 | 872 | ||
| 857 | - if (be32_to_cpu(pc_desc->pname_count) > 0) { | 873 | + fc_fpin_pname_stats_update(shost, attach_rport, event_type, |
| 858 | - for (i = 0; | 874 | + be32_to_cpu(pc_desc->desc_len), |
| 859 | - i < be32_to_cpu(pc_desc->pname_count); | 875 | + FC_TLV_DESC_LENGTH_FROM_SZ(*pc_desc), |
| 860 | - i++) { | 876 | + be32_to_cpu(pc_desc->pname_count), |
| 861 | - wwpn = be64_to_cpu(pc_desc->pname_list[i]); | 877 | + pc_desc->pname_list, fc_cn_stats_update); |
| 862 | - rport = fc_find_rport_by_wwpn(shost, wwpn); | ||
| 863 | - if (rport && | ||
| 864 | - (rport->roles & FC_PORT_ROLE_FCP_TARGET || | ||
| 865 | - rport->roles & FC_PORT_ROLE_NVME_TARGET)) { | ||
| 866 | - if (rport == attach_rport) | ||
| 867 | - continue; | ||
| 868 | - fc_cn_stats_update(event_type, | ||
| 869 | - &rport->fpin_stats); | ||
| 870 | - } | ||
| 871 | - } | ||
| 872 | - } | ||
| 873 | } | 878 | } |
| 874 | 879 | ||
| 875 | /* | 880 | /* |
| @@ -1338,11 +1338,6 @@ static void s3c64xx_spi_remove(struct platform_device *pdev) | |||
| 1338 | 1338 | ||
| 1339 | writel(0, sdd->regs + S3C64XX_SPI_INT_EN); | 1339 | writel(0, sdd->regs + S3C64XX_SPI_INT_EN); |
| 1340 | 1340 | ||
| 1341 | - if (!is_polling(sdd)) { | ||
| 1342 | - dma_release_channel(sdd->rx_dma.ch); | ||
| 1343 | - dma_release_channel(sdd->tx_dma.ch); | ||
| 1344 | - } | ||
| 1345 | - | ||
| 1346 | pm_runtime_put_noidle(&pdev->dev); | 1341 | pm_runtime_put_noidle(&pdev->dev); |
[drivers/spi/spi-s3c64xx.c:1341] 此处 ![]() ![]() | |||
| 1347 | pm_runtime_disable(&pdev->dev); | 1342 | pm_runtime_disable(&pdev->dev); |
| 1348 | pm_runtime_set_suspended(&pdev->dev); | 1343 | pm_runtime_set_suspended(&pdev->dev); |
| @@ -461,11 +461,11 @@ static int wpcm_fiu_probe(struct platform_device *pdev) | |||
| 461 | 461 | ||
| 462 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); | 462 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); |
| 463 | fiu->memory = devm_ioremap_resource(dev, res); | 463 | fiu->memory = devm_ioremap_resource(dev, res); |
| 464 | - fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); | ||
| 465 | if (IS_ERR(fiu->memory)) { | 464 | if (IS_ERR(fiu->memory)) { |
| 466 | dev_err(dev, "Failed to map flash memory window\n"); | 465 | dev_err(dev, "Failed to map flash memory window\n"); |
| 467 | return PTR_ERR(fiu->memory); | 466 | return PTR_ERR(fiu->memory); |
| 468 | } | 467 | } |
| 468 | + fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); | ||
| 469 | 469 | ||
| 470 | fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm"); | 470 | fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm"); |
| 471 | 471 | ||
| @@ -686,8 +686,10 @@ static int dw8250_probe(struct platform_device *pdev) | |||
| 686 | */ | 686 | */ |
| 687 | if (data->clk) { | 687 | if (data->clk) { |
| 688 | err = clk_notifier_register(data->clk, &data->clk_notifier); | 688 | err = clk_notifier_register(data->clk, &data->clk_notifier); |
| 689 | - if (err) | 689 | + if (err) { |
| 690 | + serial8250_unregister_port(data->data.line); | ||
| 690 | return dev_err_probe(dev, err, "Failed to set the clock notifier\n"); | 691 | return dev_err_probe(dev, err, "Failed to set the clock notifier\n"); |
| 692 | + } | ||
| 691 | queue_work(system_unbound_wq, &data->clk_work); | 693 | queue_work(system_unbound_wq, &data->clk_work); |
| 692 | } | 694 | } |
| 693 | 695 | ||
| @@ -710,6 +710,8 @@ static void ep_free(struct eventpoll *ep) | |||
| 710 | kfree(ep); | 710 | kfree(ep); |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | +static struct file *epi_fget(const struct epitem *epi); | ||
[fs/eventpoll.c:713] 添加了 ![]() ![]() | |||
| 714 | + | ||
| 713 | /* | 715 | /* |
| 714 | * Removes a "struct epitem" from the eventpoll RB tree and deallocates | 716 | * Removes a "struct epitem" from the eventpoll RB tree and deallocates |
| 715 | * all the associated resources. Must be called with "mtx" held. | 717 | * all the associated resources. Must be called with "mtx" held. |
| @@ -720,7 +722,7 @@ static void ep_free(struct eventpoll *ep) | |||
| 720 | */ | 722 | */ |
| 721 | static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) | 723 | static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) |
| 722 | { | 724 | { |
| 723 | - struct file *file = epi->ffd.file; | 725 | + struct file *file; |
| 724 | struct epitems_head *to_free; | 726 | struct epitems_head *to_free; |
| 725 | struct hlist_head *head; | 727 | struct hlist_head *head; |
| 726 | 728 | ||
| @@ -731,10 +733,23 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) | |||
| 731 | */ | 733 | */ |
| 732 | ep_unregister_pollwait(ep, epi); | 734 | ep_unregister_pollwait(ep, epi); |
| 733 | 735 | ||
| 736 | + /* cheap sync with eventpoll_release_file() */ | ||
| 737 | + if (!force && unlikely(READ_ONCE(epi->dying))) | ||
| 738 | + return false; | ||
| 739 | + | ||
| 740 | + /* | ||
| 741 | + * If we manage to grab a reference it means we're not in | ||
| 742 | + * eventpoll_release_file() and aren't going to be. | ||
| 743 | + */ | ||
| 744 | + file = epi_fget(epi); | ||
| 745 | + if (!file) | ||
| 746 | + return false; | ||
| 747 | + | ||
| 734 | /* Remove the current item from the list of epoll hooks */ | 748 | /* Remove the current item from the list of epoll hooks */ |
| 735 | spin_lock(&file->f_lock); | 749 | spin_lock(&file->f_lock); |
| 736 | if (epi->dying && !force) { | 750 | if (epi->dying && !force) { |
| 737 | spin_unlock(&file->f_lock); | 751 | spin_unlock(&file->f_lock); |
| 752 | + fput(file); | ||
| 738 | return false; | 753 | return false; |
| 739 | } | 754 | } |
| 740 | 755 | ||
| @@ -772,6 +787,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) | |||
| 772 | call_rcu(&epi->rcu, epi_rcu_free); | 787 | call_rcu(&epi->rcu, epi_rcu_free); |
| 773 | 788 | ||
| 774 | percpu_counter_dec(&ep->user->epoll_watches); | 789 | percpu_counter_dec(&ep->user->epoll_watches); |
| 790 | + fput(file); | ||
| 775 | return true; | 791 | return true; |
| 776 | } | 792 | } |
| 777 | 793 | ||
| @@ -478,8 +478,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) | |||
| 478 | { | 478 | { |
| 479 | atomic_add(blks, &sdp->sd_log_blks_free); | 479 | atomic_add(blks, &sdp->sd_log_blks_free); |
| 480 | trace_gfs2_log_blocks(sdp, blks); | 480 | trace_gfs2_log_blocks(sdp, blks); |
| 481 | - gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= | 481 | + gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || |
| 482 | - sdp->sd_jdesc->jd_blocks); | 482 | + atomic_read(&sdp->sd_log_blks_free) <= |
| 483 | + sdp->sd_jdesc->jd_blocks); | ||
| 483 | if (atomic_read(&sdp->sd_log_blks_needed)) | 484 | if (atomic_read(&sdp->sd_log_blks_needed)) |
| 484 | wake_up(&sdp->sd_log_waitq); | 485 | wake_up(&sdp->sd_log_waitq); |
| 485 | } | 486 | } |
| @@ -1122,6 +1122,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, | |||
| 1122 | struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); | 1122 | struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); |
| 1123 | unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; | 1123 | unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; |
| 1124 | int rc; | 1124 | int rc; |
| 1125 | + DECLARE_CRYPTO_WAIT(wait); | ||
| 1125 | struct scatterlist *sg; | 1126 | struct scatterlist *sg; |
| 1126 | u8 sign[SMB2_SIGNATURE_SIZE] = {}; | 1127 | u8 sign[SMB2_SIGNATURE_SIZE] = {}; |
| 1127 | u8 key[SMB3_ENC_DEC_KEY_SIZE]; | 1128 | u8 key[SMB3_ENC_DEC_KEY_SIZE]; |
| @@ -1208,12 +1209,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, | |||
| 1208 | 1209 | ||
| 1209 | aead_request_set_crypt(req, sg, sg, crypt_len, iv); | 1210 | aead_request_set_crypt(req, sg, sg, crypt_len, iv); |
| 1210 | aead_request_set_ad(req, assoc_data_len); | 1211 | aead_request_set_ad(req, assoc_data_len); |
| 1211 | - aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); | 1212 | + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | |
| 1213 | + CRYPTO_TFM_REQ_MAY_SLEEP, | ||
| 1214 | + crypto_req_done, &wait); | ||
| 1212 | 1215 | ||
| 1213 | - if (enc) | 1216 | + rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : |
| 1214 | - rc = crypto_aead_encrypt(req); | 1217 | + crypto_aead_decrypt(req), &wait); |
| 1215 | - else | ||
| 1216 | - rc = crypto_aead_decrypt(req); | ||
| 1217 | if (rc) | 1218 | if (rc) |
| 1218 | goto free_iv; | 1219 | goto free_iv; |
| 1219 | 1220 | ||
| @@ -464,8 +464,12 @@ static inline int compare_guid_key(struct oplock_info *opinfo, | |||
| 464 | const char *guid1, const char *key1) | 464 | const char *guid1, const char *key1) |
| 465 | { | 465 | { |
| 466 | const char *guid2, *key2; | 466 | const char *guid2, *key2; |
| 467 | + struct ksmbd_conn *conn; | ||
| 467 | 468 | ||
| 468 | - guid2 = opinfo->conn->ClientGUID; | 469 | + conn = READ_ONCE(opinfo->conn); |
| 470 | + if (!conn) | ||
| 471 | + return 0; | ||
| 472 | + guid2 = conn->ClientGUID; | ||
| 469 | key2 = opinfo->o_lease->lease_key; | 473 | key2 = opinfo->o_lease->lease_key; |
| 470 | if (!memcmp(guid1, guid2, SMB2_CLIENT_GUID_SIZE) && | 474 | if (!memcmp(guid1, guid2, SMB2_CLIENT_GUID_SIZE) && |
| 471 | !memcmp(key1, key2, SMB2_LEASE_KEY_SIZE)) | 475 | !memcmp(key1, key2, SMB2_LEASE_KEY_SIZE)) |
| @@ -14,7 +14,6 @@ struct tcf_pedit_key_ex { | |||
| 14 | struct tcf_pedit_parms { | 14 | struct tcf_pedit_parms { |
| 15 | struct tc_pedit_key *tcfp_keys; | 15 | struct tc_pedit_key *tcfp_keys; |
| 16 | struct tcf_pedit_key_ex *tcfp_keys_ex; | 16 | struct tcf_pedit_key_ex *tcfp_keys_ex; |
| 17 | - u32 tcfp_off_max_hint; | ||
| 18 | unsigned char tcfp_nkeys; | 17 | unsigned char tcfp_nkeys; |
| 19 | unsigned char tcfp_flags; | 18 | unsigned char tcfp_flags; |
| 20 | struct rcu_head rcu; | 19 | struct rcu_head rcu; |
| @@ -1241,7 +1241,7 @@ static ssize_t extract_kvec_to_sg(struct iov_iter *iter, | |||
| 1241 | else | 1241 | else |
| 1242 | page = virt_to_page((void *)kaddr); | 1242 | page = virt_to_page((void *)kaddr); |
| 1243 | 1243 | ||
| 1244 | - sg_set_page(sg, page, len, off); | 1244 | + sg_set_page(sg, page, seg, off); |
| 1245 | sgtable->nents++; | 1245 | sgtable->nents++; |
| 1246 | sg++; | 1246 | sg++; |
| 1247 | sg_max--; | 1247 | sg_max--; |
| @@ -1250,6 +1250,7 @@ static ssize_t extract_kvec_to_sg(struct iov_iter *iter, | |||
| 1250 | kaddr += PAGE_SIZE; | 1250 | kaddr += PAGE_SIZE; |
| 1251 | off = 0; | 1251 | off = 0; |
| 1252 | } while (len > 0 && sg_max > 0); | 1252 | } while (len > 0 && sg_max > 0); |
| 1253 | + ret -= len; | ||
| 1253 | 1254 | ||
| 1254 | if (maxsize <= 0 || sg_max == 0) | 1255 | if (maxsize <= 0 || sg_max == 0) |
| 1255 | break; | 1256 | break; |
| @@ -1342,7 +1343,7 @@ ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t maxsize, | |||
| 1342 | struct sg_table *sgtable, unsigned int sg_max, | 1343 | struct sg_table *sgtable, unsigned int sg_max, |
| 1343 | iov_iter_extraction_t extraction_flags) | 1344 | iov_iter_extraction_t extraction_flags) |
| 1344 | { | 1345 | { |
| 1345 | - if (maxsize == 0) | 1346 | + if (maxsize == 0 || sg_max == 0) |
| 1346 | return 0; | 1347 | return 0; |
| 1347 | 1348 | ||
| 1348 | switch (iov_iter_type(iter)) { | 1349 | switch (iov_iter_type(iter)) { |
| @@ -210,6 +210,12 @@ static int memfd_add_seals(struct file *file, unsigned int seals) | |||
| 210 | goto unlock; | 210 | goto unlock; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | + /* | ||
| 214 | + * SEAL_EXEC implies SEAL_WRITE, making W^X from the start. | ||
| 215 | + */ | ||
| 216 | + if (seals & F_SEAL_EXEC && inode->i_mode & 0111) | ||
| 217 | + seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; | ||
| 218 | + | ||
| 213 | if ((seals & F_SEAL_WRITE) && !(*file_seals & F_SEAL_WRITE)) { | 219 | if ((seals & F_SEAL_WRITE) && !(*file_seals & F_SEAL_WRITE)) { |
| 214 | error = mapping_deny_writable(file->f_mapping); | 220 | error = mapping_deny_writable(file->f_mapping); |
| 215 | if (error) | 221 | if (error) |
| @@ -222,12 +228,6 @@ static int memfd_add_seals(struct file *file, unsigned int seals) | |||
| 222 | } | 228 | } |
| 223 | } | 229 | } |
| 224 | 230 | ||
| 225 | - /* | ||
| 226 | - * SEAL_EXEC implys SEAL_WRITE, making W^X from the start. | ||
| 227 | - */ | ||
| 228 | - if (seals & F_SEAL_EXEC && inode->i_mode & 0111) | ||
| 229 | - seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; | ||
| 230 | - | ||
| 231 | *file_seals |= seals; | 231 | *file_seals |= seals; |
| 232 | error = 0; | 232 | error = 0; |
| 233 | 233 | ||
| @@ -4348,6 +4348,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) | |||
| 4348 | struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); | 4348 | struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); |
| 4349 | 4349 | ||
| 4350 | master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); | 4350 | master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); |
| 4351 | + if (unlikely(!(master->flags & IFF_UP))) | ||
| 4352 | + return XDP_ABORTED; | ||
| 4351 | slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); | 4353 | slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); |
| 4352 | if (slave && slave != xdp->rxq->dev) { | 4354 | if (slave && slave != xdp->rxq->dev) { |
| 4353 | /* The target device is different from the receiving device, so | 4355 | /* The target device is different from the receiving device, so |
| @@ -1350,16 +1350,13 @@ bool __skb_flow_dissect(const struct net *net, | |||
| 1350 | break; | 1350 | break; |
| 1351 | } | 1351 | } |
| 1352 | 1352 | ||
| 1353 | - /* least significant bit of the most significant octet | 1353 | + /* PFC (compressed 1-byte protocol) frames are not processed. |
| 1354 | - * indicates if protocol field was compressed | 1354 | + * A compressed protocol field has the least significant bit of |
| 1355 | + * the most significant octet set, which will fail the following | ||
| 1356 | + * ppp_proto_is_valid(), returning FLOW_DISSECT_RET_OUT_BAD. | ||
| 1355 | */ | 1357 | */ |
| 1356 | ppp_proto = ntohs(hdr->proto); | 1358 | ppp_proto = ntohs(hdr->proto); |
| 1357 | - if (ppp_proto & 0x0100) { | 1359 | + nhoff += PPPOE_SES_HLEN; |
| 1358 | - ppp_proto = ppp_proto >> 8; | ||
| 1359 | - nhoff += PPPOE_SES_HLEN - 1; | ||
| 1360 | - } else { | ||
| 1361 | - nhoff += PPPOE_SES_HLEN; | ||
| 1362 | - } | ||
| 1363 | 1360 | ||
| 1364 | if (ppp_proto == PPP_IP) { | 1361 | if (ppp_proto == PPP_IP) { |
| 1365 | proto = htons(ETH_P_IP); | 1362 | proto = htons(ETH_P_IP); |
| @@ -113,6 +113,9 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) | |||
| 113 | if (p->pp_recycle != skb->pp_recycle) | 113 | if (p->pp_recycle != skb->pp_recycle) |
| 114 | return -ETOOMANYREFS; | 114 | return -ETOOMANYREFS; |
| 115 | 115 | ||
| 116 | + if (skb_zcopy(p) || skb_zcopy(skb)) | ||
| 117 | + return -ETOOMANYREFS; | ||
| 118 | + | ||
| 116 | if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || | 119 | if (unlikely(p->len + len >= netif_get_gro_max_size(p->dev, p) || |
| 117 | NAPI_GRO_CB(skb)->flush)) | 120 | NAPI_GRO_CB(skb)->flush)) |
| 118 | return -E2BIG; | 121 | return -E2BIG; |
| @@ -1112,8 +1112,8 @@ static int __ip_append_data(struct sock *sk, | |||
| 1112 | !(rt->dst.dev->features & NETIF_F_SG))) | 1112 | !(rt->dst.dev->features & NETIF_F_SG))) |
| 1113 | alloclen = fraglen; | 1113 | alloclen = fraglen; |
| 1114 | else { | 1114 | else { |
| 1115 | - alloclen = fragheaderlen + transhdrlen; | 1115 | + alloclen = fragheaderlen + transhdrlen + fraggap; |
| 1116 | - pagedlen = datalen - transhdrlen; | 1116 | + pagedlen = datalen - transhdrlen - fraggap; |
| 1117 | } | 1117 | } |
| 1118 | 1118 | ||
| 1119 | alloclen += alloc_extra; | 1119 | alloclen += alloc_extra; |
| @@ -1694,8 +1694,8 @@ static int __ip6_append_data(struct sock *sk, | |||
| 1694 | !(rt->dst.dev->features & NETIF_F_SG))) | 1694 | !(rt->dst.dev->features & NETIF_F_SG))) |
| 1695 | alloclen = fraglen; | 1695 | alloclen = fraglen; |
| 1696 | else { | 1696 | else { |
| 1697 | - alloclen = fragheaderlen + transhdrlen; | 1697 | + alloclen = fragheaderlen + transhdrlen + fraggap; |
| 1698 | - pagedlen = datalen - transhdrlen; | 1698 | + pagedlen = datalen - transhdrlen - fraggap; |
| 1699 | } | 1699 | } |
| 1700 | alloclen += alloc_extra; | 1700 | alloclen += alloc_extra; |
| 1701 | 1701 | ||
| @@ -484,6 +484,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res, | |||
| 484 | const struct fib6_nh *nh = sibling->fib6_nh; | 484 | const struct fib6_nh *nh = sibling->fib6_nh; |
| 485 | int nh_upper_bound; | 485 | int nh_upper_bound; |
| 486 | 486 | ||
| 487 | + if (!READ_ONCE(first->fib6_nsiblings)) | ||
| 488 | + break; | ||
| 489 | + | ||
| 487 | nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); | 490 | nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); |
| 488 | if (hash > nh_upper_bound) | 491 | if (hash > nh_upper_bound) |
| 489 | continue; | 492 | continue; |
| @@ -4822,6 +4822,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, | |||
| 4822 | u8 sa[ETH_ALEN]; | 4822 | u8 sa[ETH_ALEN]; |
| 4823 | } addrs __aligned(2); | 4823 | } addrs __aligned(2); |
| 4824 | struct ieee80211_sta_rx_stats *stats; | 4824 | struct ieee80211_sta_rx_stats *stats; |
| 4825 | + u32 encoded_rate; | ||
| 4825 | 4826 | ||
| 4826 | /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write | 4827 | /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write |
| 4827 | * to a common data structure; drivers can implement that per queue | 4828 | * to a common data structure; drivers can implement that per queue |
| @@ -4924,6 +4925,9 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, | |||
| 4924 | /* push the addresses in front */ | 4925 | /* push the addresses in front */ |
| 4925 | memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); | 4926 | memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); |
| 4926 | 4927 | ||
| 4928 | + /* capture before mesh forward may memset or free skb->cb */ | ||
| 4929 | + encoded_rate = sta_stats_encode_rate(status); | ||
| 4930 | + | ||
| 4927 | res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb); | 4931 | res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb); |
| 4928 | switch (res) { | 4932 | switch (res) { |
| 4929 | case RX_QUEUED: | 4933 | case RX_QUEUED: |
| @@ -156,7 +156,6 @@ static int nft_inner_parse_l2l3(const struct nft_inner *priv, | |||
| 156 | return -1; | 156 | return -1; |
| 157 | 157 | ||
| 158 | if (fragoff == 0) { | 158 | if (fragoff == 0) { |
| 159 | - thoff = nhoff + sizeof(_ip6h); | ||
| 160 | ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH; | 159 | ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH; |
| 161 | ctx->inner_thoff = thoff; | 160 | ctx->inner_thoff = thoff; |
| 162 | ctx->l4proto = l4proto; | 161 | ctx->l4proto = l4proto; |
| @@ -16,6 +16,8 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 20 | + | ||
| 19 | 21 | ||
| 20 | 22 | ||
| 21 | 23 | ||
| @@ -242,7 +244,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, | |||
| 242 | goto out_free_ex; | 244 | goto out_free_ex; |
| 243 | } | 245 | } |
| 244 | 246 | ||
| 245 | - nparms->tcfp_off_max_hint = 0; | ||
| 246 | nparms->tcfp_flags = parm->flags; | 247 | nparms->tcfp_flags = parm->flags; |
| 247 | nparms->tcfp_nkeys = parm->nkeys; | 248 | nparms->tcfp_nkeys = parm->nkeys; |
| 248 | 249 | ||
| @@ -268,14 +269,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, | |||
| 268 | BITS_PER_TYPE(int) - 1, | 269 | BITS_PER_TYPE(int) - 1, |
| 269 | nparms->tcfp_keys[i].shift); | 270 | nparms->tcfp_keys[i].shift); |
| 270 | 271 | ||
| 271 | - /* The AT option can read a single byte, we can bound the actual | ||
| 272 | - * value with uchar max. | ||
| 273 | - */ | ||
| 274 | - cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift; | ||
| 275 | - | ||
| 276 | - /* Each key touches 4 bytes starting from the computed offset */ | ||
| 277 | - nparms->tcfp_off_max_hint = | ||
| 278 | - max(nparms->tcfp_off_max_hint, cur + 4); | ||
| 279 | } | 272 | } |
| 280 | 273 | ||
| 281 | p = to_pedit(*a); | 274 | p = to_pedit(*a); |
| @@ -318,15 +311,12 @@ static void tcf_pedit_cleanup(struct tc_action *a) | |||
| 318 | call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu); | 311 | call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu); |
| 319 | } | 312 | } |
| 320 | 313 | ||
| 321 | -static bool offset_valid(struct sk_buff *skb, int offset) | 314 | +static bool offset_valid(struct sk_buff *skb, int offset, int len) |
| 322 | { | 315 | { |
| 323 | - if (offset > 0 && offset > skb->len) | 316 | + if (offset < -(int)skb_headroom(skb)) |
| 324 | return false; | 317 | return false; |
| 325 | 318 | ||
| 326 | - if (offset < 0 && -offset > skb_headroom(skb)) | 319 | + return offset <= (int)skb->len - len; |
| 327 | - return false; | ||
| 328 | - | ||
| 329 | - return true; | ||
| 330 | } | 320 | } |
| 331 | 321 | ||
| 332 | static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type) | 322 | static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type) |
| @@ -393,18 +383,10 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, | |||
| 393 | struct tcf_pedit_key_ex *tkey_ex; | 383 | struct tcf_pedit_key_ex *tkey_ex; |
| 394 | struct tcf_pedit_parms *parms; | 384 | struct tcf_pedit_parms *parms; |
| 395 | struct tc_pedit_key *tkey; | 385 | struct tc_pedit_key *tkey; |
| 396 | - u32 max_offset; | ||
| 397 | int i; | 386 | int i; |
| 398 | 387 | ||
| 399 | parms = rcu_dereference_bh(p->parms); | 388 | parms = rcu_dereference_bh(p->parms); |
| 400 | 389 | ||
| 401 | - max_offset = (skb_transport_header_was_set(skb) ? | ||
| 402 | - skb_transport_offset(skb) : | ||
| 403 | - skb_network_offset(skb)) + | ||
| 404 | - parms->tcfp_off_max_hint; | ||
| 405 | - if (skb_ensure_writable(skb, min(skb->len, max_offset))) | ||
| 406 | - goto done; | ||
| 407 | - | ||
| 408 | tcf_lastuse_update(&p->tcf_tm); | 390 | tcf_lastuse_update(&p->tcf_tm); |
| 409 | tcf_action_update_bstats(&p->common, skb); | 391 | tcf_action_update_bstats(&p->common, skb); |
| 410 | 392 | ||
| @@ -412,10 +394,11 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, | |||
| 412 | tkey_ex = parms->tcfp_keys_ex; | 394 | tkey_ex = parms->tcfp_keys_ex; |
| 413 | 395 | ||
| 414 | for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { | 396 | for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { |
| 397 | + int write_offset, write_len; | ||
| 415 | int offset = tkey->off; | 398 | int offset = tkey->off; |
| 416 | int hoffset = 0; | 399 | int hoffset = 0; |
| 417 | - u32 *ptr, hdata; | 400 | + u32 cur_val, val; |
| 418 | - u32 val; | 401 | + u32 *ptr; |
| 419 | int rc; | 402 | int rc; |
| 420 | 403 | ||
| 421 | if (tkey_ex) { | 404 | if (tkey_ex) { |
| @@ -433,13 +416,15 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, | |||
| 433 | 416 | ||
| 434 | if (tkey->offmask) { | 417 | if (tkey->offmask) { |
| 435 | u8 *d, _d; | 418 | u8 *d, _d; |
| 419 | + int at_offset; | ||
| 436 | 420 | ||
| 437 | - if (!offset_valid(skb, hoffset + tkey->at)) { | 421 | + if (check_add_overflow(hoffset, (int)tkey->at, &at_offset) || |
| 422 | + !offset_valid(skb, at_offset, sizeof(_d))) { | ||
| 438 | pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n", | 423 | pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n", |
| 439 | hoffset + tkey->at); | 424 | hoffset + tkey->at); |
| 440 | goto bad; | 425 | goto bad; |
| 441 | } | 426 | } |
| 442 | - d = skb_header_pointer(skb, hoffset + tkey->at, | 427 | + d = skb_header_pointer(skb, at_offset, |
| 443 | sizeof(_d), &_d); | 428 | sizeof(_d), &_d); |
| 444 | if (!d) | 429 | if (!d) |
| 445 | goto bad; | 430 | goto bad; |
| @@ -451,31 +436,51 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, | |||
| 451 | } | 436 | } |
| 452 | } | 437 | } |
| 453 | 438 | ||
| 454 | - if (!offset_valid(skb, hoffset + offset)) { | 439 | + if (check_add_overflow(hoffset, offset, &write_offset)) { |
| 455 | - pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset); | 440 | + pr_info_ratelimited("tc action pedit offset overflow\n"); |
| 456 | goto bad; | 441 | goto bad; |
| 457 | } | 442 | } |
| 458 | 443 | ||
| 459 | - ptr = skb_header_pointer(skb, hoffset + offset, | 444 | + if (!offset_valid(skb, write_offset, sizeof(*ptr))) { |
| 460 | - sizeof(hdata), &hdata); | 445 | + pr_info_ratelimited("tc action pedit offset %d out of bounds\n", |
| 461 | - if (!ptr) | 446 | + write_offset); |
| 462 | goto bad; | 447 | goto bad; |
| 448 | + } | ||
| 449 | + | ||
| 450 | + if (write_offset < 0) { | ||
| 451 | + if (skb_cow(skb, -write_offset)) | ||
| 452 | + goto bad; | ||
| 453 | + if (write_offset + (int)sizeof(*ptr) > 0) { | ||
| 454 | + if (skb_ensure_writable(skb, | ||
| 455 | + min_t(int, skb->len, | ||
| 456 | + write_offset + (int)sizeof(*ptr)))) | ||
| 457 | + goto bad; | ||
| 458 | + } | ||
| 459 | + } else { | ||
| 460 | + if (check_add_overflow(write_offset, (int)sizeof(*ptr), | ||
| 461 | + &write_len)) | ||
| 462 | + goto bad; | ||
| 463 | + if (skb_ensure_writable(skb, min_t(int, skb->len, | ||
| 464 | + write_len))) | ||
| 465 | + goto bad; | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + ptr = (u32 *)(skb->data + write_offset); | ||
| 469 | + cur_val = get_unaligned(ptr); | ||
| 463 | /* just do it, baby */ | 470 | /* just do it, baby */ |
| 464 | switch (cmd) { | 471 | switch (cmd) { |
| 465 | case TCA_PEDIT_KEY_EX_CMD_SET: | 472 | case TCA_PEDIT_KEY_EX_CMD_SET: |
| 466 | val = tkey->val; | 473 | val = tkey->val; |
| 467 | break; | 474 | break; |
| 468 | case TCA_PEDIT_KEY_EX_CMD_ADD: | 475 | case TCA_PEDIT_KEY_EX_CMD_ADD: |
| 469 | - val = (*ptr + tkey->val) & ~tkey->mask; | 476 | + val = (cur_val + tkey->val) & ~tkey->mask; |
| 470 | break; | 477 | break; |
| 471 | default: | 478 | default: |
| 472 | pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd); | 479 | pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd); |
| 473 | goto bad; | 480 | goto bad; |
| 474 | } | 481 | } |
| 475 | 482 | ||
| 476 | - *ptr = ((*ptr & tkey->mask) ^ val); | 483 | + put_unaligned((cur_val & tkey->mask) ^ val, ptr); |
| 477 | - if (ptr == &hdata) | ||
| 478 | - skb_store_bits(skb, hoffset + offset, ptr, 4); | ||
| 479 | } | 484 | } |
| 480 | 485 | ||
| 481 | goto done; | 486 | goto done; |
| @@ -1204,6 +1204,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( | |||
| 1204 | /* Skip over the ADDIP header and find the Address parameter */ | 1204 | /* Skip over the ADDIP header and find the Address parameter */ |
| 1205 | param = (union sctp_addr_param *)(asconf + 1); | 1205 | param = (union sctp_addr_param *)(asconf + 1); |
| 1206 | 1206 | ||
| 1207 | + /* The whole address parameter must lie within the chunk before | ||
| 1208 | + * af->from_addr_param() reads the variable-length address; otherwise a | ||
| 1209 | + * truncated trailing ASCONF chunk lets it read uninitialized bytes past | ||
| 1210 | + * the parameter. | ||
| 1211 | + */ | ||
| 1212 | + if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) | ||
| 1213 | + return NULL; | ||
| 1214 | + | ||
| 1207 | af = sctp_get_af_specific(param_type2af(param->p.type)); | 1215 | af = sctp_get_af_specific(param_type2af(param->p.type)); |
| 1208 | if (unlikely(!af)) | 1216 | if (unlikely(!af)) |
| 1209 | return NULL; | 1217 | return NULL; |
| @@ -263,9 +263,12 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t) | |||
| 263 | skb_set_inner_ipproto(skb, IPPROTO_SCTP); | 263 | skb_set_inner_ipproto(skb, IPPROTO_SCTP); |
| 264 | label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6); | 264 | label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6); |
| 265 | 265 | ||
| 266 | - return udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, | 266 | + local_bh_disable(); |
| 267 | - &fl6->daddr, tclass, ip6_dst_hoplimit(dst), | 267 | + udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, |
| 268 | - label, sctp_sk(sk)->udp_port, t->encap_port, false); | 268 | + &fl6->daddr, tclass, ip6_dst_hoplimit(dst), |
| 269 | + label, sctp_sk(sk)->udp_port, t->encap_port, false); | ||
| 270 | + local_bh_enable(); | ||
| 271 | + return 0; | ||
| 269 | } | 272 | } |
| 270 | 273 | ||
| 271 | /* Returns the dst cache entry for the given source and destination ip | 274 | /* Returns the dst cache entry for the given source and destination ip |
| @@ -1085,9 +1085,11 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t) | |||
| 1085 | skb_reset_inner_mac_header(skb); | 1085 | skb_reset_inner_mac_header(skb); |
| 1086 | skb_reset_inner_transport_header(skb); | 1086 | skb_reset_inner_transport_header(skb); |
| 1087 | skb_set_inner_ipproto(skb, IPPROTO_SCTP); | 1087 | skb_set_inner_ipproto(skb, IPPROTO_SCTP); |
| 1088 | + local_bh_disable(); | ||
| 1088 | udp_tunnel_xmit_skb((struct rtable *)dst, sk, skb, fl4->saddr, | 1089 | udp_tunnel_xmit_skb((struct rtable *)dst, sk, skb, fl4->saddr, |
| 1089 | fl4->daddr, dscp, ip4_dst_hoplimit(dst), df, | 1090 | fl4->daddr, dscp, ip4_dst_hoplimit(dst), df, |
| 1090 | sctp_sk(sk)->udp_port, t->encap_port, false, false); | 1091 | sctp_sk(sk)->udp_port, t->encap_port, false, false); |
| 1092 | + local_bh_enable(); | ||
| 1091 | return 0; | 1093 | return 0; |
| 1092 | } | 1094 | } |
| 1093 | 1095 | ||
| @@ -3361,11 +3361,10 @@ int smc_create_clcsk(struct net *net, struct sock *sk, int family) | |||
| 3361 | return 0; | 3361 | return 0; |
| 3362 | } | 3362 | } |
| 3363 | 3363 | ||
| 3364 | -static int __smc_create(struct net *net, struct socket *sock, int protocol, | 3364 | +static int smc_create(struct net *net, struct socket *sock, int protocol, |
| 3365 | - int kern, struct socket *clcsock) | 3365 | + int kern) |
| 3366 | { | 3366 | { |
| 3367 | int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET; | 3367 | int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET; |
| 3368 | - struct smc_sock *smc; | ||
| 3369 | struct sock *sk; | 3368 | struct sock *sk; |
| 3370 | int rc; | 3369 | int rc; |
| 3371 | 3370 | ||
| @@ -3384,88 +3383,17 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol, | |||
| 3384 | if (!sk) | 3383 | if (!sk) |
| 3385 | goto out; | 3384 | goto out; |
| 3386 | 3385 | ||
| 3387 | - /* create internal TCP socket for CLC handshake and fallback */ | 3386 | + rc = smc_create_clcsk(net, sk, family); |
| 3388 | - smc = smc_sk(sk); | ||
| 3389 | - | ||
| 3390 | - rc = 0; | ||
| 3391 | - if (clcsock) | ||
| 3392 | - smc->clcsock = clcsock; | ||
| 3393 | - else | ||
| 3394 | - rc = smc_create_clcsk(net, sk, family); | ||
| 3395 | out: | 3387 | out: |
| 3396 | return rc; | 3388 | return rc; |
| 3397 | } | 3389 | } |
| 3398 | 3390 | ||
| 3399 | -static int smc_create(struct net *net, struct socket *sock, int protocol, | ||
| 3400 | - int kern) | ||
| 3401 | -{ | ||
| 3402 | - return __smc_create(net, sock, protocol, kern, NULL); | ||
| 3403 | -} | ||
| 3404 | - | ||
| 3405 | static const struct net_proto_family smc_sock_family_ops = { | 3391 | static const struct net_proto_family smc_sock_family_ops = { |
| 3406 | .family = PF_SMC, | 3392 | .family = PF_SMC, |
| 3407 | .owner = THIS_MODULE, | 3393 | .owner = THIS_MODULE, |
| 3408 | .create = smc_create, | 3394 | .create = smc_create, |
| 3409 | }; | 3395 | }; |
| 3410 | 3396 | ||
| 3411 | -static int smc_ulp_init(struct sock *sk) | ||
| 3412 | -{ | ||
| 3413 | - struct socket *tcp = sk->sk_socket; | ||
| 3414 | - struct net *net = sock_net(sk); | ||
| 3415 | - struct socket *smcsock; | ||
| 3416 | - int protocol, ret; | ||
| 3417 | - | ||
| 3418 | - /* only TCP can be replaced */ | ||
| 3419 | - if (tcp->type != SOCK_STREAM || sk->sk_protocol != IPPROTO_TCP || | ||
| 3420 | - (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)) | ||
| 3421 | - return -ESOCKTNOSUPPORT; | ||
| 3422 | - /* don't handle wq now */ | ||
| 3423 | - if (tcp->state != SS_UNCONNECTED || !tcp->file || tcp->wq.fasync_list) | ||
| 3424 | - return -ENOTCONN; | ||
| 3425 | - | ||
| 3426 | - if (sk->sk_family == AF_INET) | ||
| 3427 | - protocol = SMCPROTO_SMC; | ||
| 3428 | - else | ||
| 3429 | - protocol = SMCPROTO_SMC6; | ||
| 3430 | - | ||
| 3431 | - smcsock = sock_alloc(); | ||
| 3432 | - if (!smcsock) | ||
| 3433 | - return -ENFILE; | ||
| 3434 | - | ||
| 3435 | - smcsock->type = SOCK_STREAM; | ||
| 3436 | - __module_get(THIS_MODULE); /* tried in __tcp_ulp_find_autoload */ | ||
| 3437 | - ret = __smc_create(net, smcsock, protocol, 1, tcp); | ||
| 3438 | - if (ret) { | ||
| 3439 | - sock_release(smcsock); /* module_put() which ops won't be NULL */ | ||
| 3440 | - return ret; | ||
| 3441 | - } | ||
| 3442 | - | ||
| 3443 | - /* replace tcp socket to smc */ | ||
| 3444 | - smcsock->file = tcp->file; | ||
| 3445 | - smcsock->file->private_data = smcsock; | ||
| 3446 | - smcsock->file->f_inode = SOCK_INODE(smcsock); /* replace inode when sock_close */ | ||
| 3447 | - smcsock->file->f_path.dentry->d_inode = SOCK_INODE(smcsock); /* dput() in __fput */ | ||
| 3448 | - tcp->file = NULL; | ||
| 3449 | - | ||
| 3450 | - return ret; | ||
| 3451 | -} | ||
| 3452 | - | ||
| 3453 | -static void smc_ulp_clone(const struct request_sock *req, struct sock *newsk, | ||
| 3454 | - const gfp_t priority) | ||
| 3455 | -{ | ||
| 3456 | - struct inet_connection_sock *icsk = inet_csk(newsk); | ||
| 3457 | - | ||
| 3458 | - /* don't inherit ulp ops to child when listen */ | ||
| 3459 | - icsk->icsk_ulp_ops = NULL; | ||
| 3460 | -} | ||
| 3461 | - | ||
| 3462 | -static struct tcp_ulp_ops smc_ulp_ops __read_mostly = { | ||
| 3463 | - .name = "smc", | ||
| 3464 | - .owner = THIS_MODULE, | ||
| 3465 | - .init = smc_ulp_init, | ||
| 3466 | - .clone = smc_ulp_clone, | ||
| 3467 | -}; | ||
| 3468 | - | ||
| 3469 | unsigned int smc_net_id; | 3397 | unsigned int smc_net_id; |
| 3470 | 3398 | ||
| 3471 | static __net_init int smc_net_init(struct net *net) | 3399 | static __net_init int smc_net_init(struct net *net) |
| @@ -3589,12 +3517,6 @@ static int __init smc_init(void) | |||
| 3589 | goto out_sock; | 3517 | goto out_sock; |
| 3590 | } | 3518 | } |
| 3591 | 3519 | ||
| 3592 | - rc = tcp_register_ulp(&smc_ulp_ops); | ||
| 3593 | - if (rc) { | ||
| 3594 | - pr_err("%s: tcp_ulp_register fails with %d\n", __func__, rc); | ||
| 3595 | - goto out_ib; | ||
| 3596 | - } | ||
| 3597 | - | ||
| 3598 | static_branch_enable(&tcp_have_smc); | 3520 | static_branch_enable(&tcp_have_smc); |
| 3599 | return 0; | 3521 | return 0; |
| 3600 | 3522 | ||
| @@ -3632,7 +3554,6 @@ static int __init smc_init(void) | |||
| 3632 | static void __exit smc_exit(void) | 3554 | static void __exit smc_exit(void) |
| 3633 | { | 3555 | { |
| 3634 | static_branch_disable(&tcp_have_smc); | 3556 | static_branch_disable(&tcp_have_smc); |
| 3635 | - tcp_unregister_ulp(&smc_ulp_ops); | ||
| 3636 | sock_unregister(PF_SMC); | 3557 | sock_unregister(PF_SMC); |
| 3637 | smc_core_exit(); | 3558 | smc_core_exit(); |
| 3638 | smc_ib_unregister_client(); | 3559 | smc_ib_unregister_client(); |
| @@ -3657,5 +3578,4 @@ MODULE_AUTHOR("Ursula Braun <ubraun@linux.vnet.ibm.com>"); | |||
| 3657 | MODULE_DESCRIPTION("smc socket address family"); | 3578 | MODULE_DESCRIPTION("smc socket address family"); |
| 3658 | MODULE_LICENSE("GPL"); | 3579 | MODULE_LICENSE("GPL"); |
| 3659 | MODULE_ALIAS_NETPROTO(PF_SMC); | 3580 | MODULE_ALIAS_NETPROTO(PF_SMC); |
| 3660 | -MODULE_ALIAS_TCP_ULP("smc"); | ||
| 3661 | MODULE_ALIAS_GENL_FAMILY(SMC_GENL_FAMILY_NAME); | 3581 | MODULE_ALIAS_GENL_FAMILY(SMC_GENL_FAMILY_NAME); |
| @@ -3558,15 +3558,14 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) | |||
| 3558 | struct bpf_prog *prog; | 3558 | struct bpf_prog *prog; |
| 3559 | struct sock *sk = v; | 3559 | struct sock *sk = v; |
| 3560 | uid_t uid; | 3560 | uid_t uid; |
| 3561 | - bool slow; | ||
| 3562 | int ret; | 3561 | int ret; |
| 3563 | 3562 | ||
| 3564 | if (v == SEQ_START_TOKEN) | 3563 | if (v == SEQ_START_TOKEN) |
| 3565 | return 0; | 3564 | return 0; |
| 3566 | 3565 | ||
| 3567 | - slow = lock_sock_fast(sk); | 3566 | + lock_sock(sk); |
| 3568 | 3567 | ||
| 3569 | - if (unlikely(sk_unhashed(sk))) { | 3568 | + if (unlikely(sock_flag(sk, SOCK_DEAD))) { |
| 3570 | ret = SEQ_SKIP; | 3569 | ret = SEQ_SKIP; |
| 3571 | goto unlock; | 3570 | goto unlock; |
| 3572 | } | 3571 | } |
| @@ -3576,7 +3575,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) | |||
| 3576 | prog = bpf_iter_get_info(&meta, false); | 3575 | prog = bpf_iter_get_info(&meta, false); |
| 3577 | ret = unix_prog_seq_show(prog, &meta, v, uid); | 3576 | ret = unix_prog_seq_show(prog, &meta, v, uid); |
| 3578 | unlock: | 3577 | unlock: |
| 3579 | - unlock_sock_fast(sk, slow); | 3578 | + release_sock(sk); |
| 3580 | return ret; | 3579 | return ret; |
| 3581 | } | 3580 | } |
| 3582 | 3581 | ||
| @@ -552,6 +552,8 @@ static void __unix_gc(struct work_struct *work) | |||
| 552 | struct sk_buff_head hitlist; | 552 | struct sk_buff_head hitlist; |
| 553 | struct sk_buff *skb; | 553 | struct sk_buff *skb; |
| 554 | 554 | ||
| 555 | + WRITE_ONCE(gc_in_progress, true); | ||
| 556 | + | ||
| 555 | spin_lock(&unix_gc_lock); | 557 | spin_lock(&unix_gc_lock); |
| 556 | 558 | ||
| 557 | if (!unix_graph_maybe_cyclic) { | 559 | if (!unix_graph_maybe_cyclic) { |
| @@ -582,7 +584,6 @@ static DECLARE_WORK(unix_gc_work, __unix_gc); | |||
| 582 | 584 | ||
| 583 | void unix_gc(void) | 585 | void unix_gc(void) |
| 584 | { | 586 | { |
| 585 | - WRITE_ONCE(gc_in_progress, true); | ||
| 586 | queue_work(system_unbound_wq, &unix_gc_work); | 587 | queue_work(system_unbound_wq, &unix_gc_work); |
| 587 | } | 588 | } |
| 588 | 589 | ||
| @@ -674,6 +674,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) | |||
| 674 | { | 674 | { |
| 675 | struct wm_coeff_ctl *ctl = cs_ctl->priv; | 675 | struct wm_coeff_ctl *ctl = cs_ctl->priv; |
| 676 | 676 | ||
| 677 | + if (!ctl) | ||
| 678 | + return; | ||
| 679 | + | ||
| 677 | cancel_work_sync(&ctl->work); | 680 | cancel_work_sync(&ctl->work); |
| 678 | 681 | ||
| 679 | kfree(ctl->name); | 682 | kfree(ctl->name); |
| @@ -903,9 +903,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, | |||
| 903 | struct audioreach_container *cont; | 903 | struct audioreach_container *cont; |
| 904 | struct audioreach_module *mod; | 904 | struct audioreach_module *mod; |
| 905 | 905 | ||
| 906 | - mod = dobj->private; | ||
| 907 | - cont = mod->container; | ||
| 908 | - | ||
| 909 | if (w->id == snd_soc_dapm_mixer) { | 906 | if (w->id == snd_soc_dapm_mixer) { |
| 910 | /* virtual widget */ | 907 | /* virtual widget */ |
| 911 | struct snd_ar_control *scontrol = dobj->private; | 908 | struct snd_ar_control *scontrol = dobj->private; |
| @@ -914,6 +911,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, | |||
| 914 | kfree(scontrol); | 911 | kfree(scontrol); |
| 915 | return 0; | 912 | return 0; |
| 916 | } | 913 | } |
| 914 | + mod = dobj->private; | ||
| 915 | + if (!mod) | ||
| 916 | + return 0; | ||
| 917 | + | ||
| 918 | + cont = mod->container; | ||
| 917 | 919 | ||
| 918 | mutex_lock(&apm->lock); | 920 | mutex_lock(&apm->lock); |
| 919 | idr_remove(&apm->modules_idr, mod->instance_id); | 921 | idr_remove(&apm->modules_idr, mod->instance_id); |


[drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h:378] 新增
struct drm_connector *connector_ptr后,原有的嵌入成员struct drm_connector connector;变成死代码。该嵌入结构体不再被使用,但仍然占用内存且容易造成混淆。建议移除struct drm_connector connector;或在提交说明中解释保留原因。同时确认所有引用mhdp->connector的代码已全部替换为mhdp->connector_ptr。