diff --git a/android/GKI_VERSION b/android/GKI_VERSION index 09132c75e562..b5da3a116844 100644 --- a/android/GKI_VERSION +++ b/android/GKI_VERSION @@ -1 +1 @@ -LTS_5.4.226_d72fdcc7094f +LTS_5.4.226_2af3bdf29330 diff --git a/android/abi_gki_aarch64.xml b/android/abi_gki_aarch64.xml index cf6642ccf4ba..e2ca86c05577 100644 --- a/android/abi_gki_aarch64.xml +++ b/android/abi_gki_aarch64.xml @@ -2075,6 +2075,7 @@ + @@ -17861,7 +17862,7 @@ - + @@ -26713,7 +26714,32 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -28598,7 +28624,7 @@ - + @@ -28981,6 +29007,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -29339,7 +29466,7 @@ - + @@ -30019,7 +30146,7 @@ - + @@ -30061,7 +30188,22 @@ - + + + + + + + + + + + + + + + + @@ -30266,6 +30408,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -30301,6 +30498,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -30929,13 +31154,27 @@ - + + + + + + + + + + + + + + + @@ -30956,6 +31195,12 @@ + + + + + + @@ -31225,26 +31470,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -31271,6 +31496,20 @@ + + + + + + + + + + + + + + @@ -31328,12 +31567,18 @@ - + - + + + + - + + + + @@ -31769,6 +32014,15 @@ + + + + + + + + + @@ -31796,6 +32050,7 @@ + @@ -31809,6 +32064,9 @@ + + + @@ -31824,6 +32082,14 @@ + + + + + + + + @@ -31890,6 +32156,14 @@ + + + + + + + + @@ -32037,20 +32311,6 @@ - - - - - - - - - - - - - - @@ -32079,20 +32339,6 @@ - - - - - - - - - - - - - - @@ -32299,7 +32545,7 @@ - + @@ -32372,6 +32618,9 @@ + + + @@ -32404,14 +32653,6 @@ - - - - - - - - @@ -32677,9 +32918,6 @@ - - - @@ -61583,7 +61821,7 @@ - + @@ -61765,7 +62003,7 @@ - + @@ -63737,7 +63975,7 @@ - + @@ -63794,7 +64032,7 @@ - + @@ -70798,7 +71036,7 @@ - + @@ -72287,7 +72525,7 @@ - + @@ -73244,7 +73482,7 @@ - + @@ -75754,7 +75992,7 @@ - + @@ -76188,7 +76426,7 @@ - + @@ -77402,7 +77640,7 @@ - + @@ -84230,11 +84468,11 @@ - + - + @@ -84334,13 +84572,13 @@ - + - + @@ -84423,7 +84661,7 @@ - + @@ -84821,7 +85059,7 @@ - + @@ -107810,7 +108048,7 @@ - + @@ -107834,7 +108072,7 @@ - + @@ -114327,8 +114565,8 @@ - - + + @@ -166888,9 +167126,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -167026,7 +167464,18 @@ + + + + + + + + + + + @@ -167215,6 +167664,13 @@ + + + + + + + @@ -167222,6 +167678,10 @@ + + + + @@ -174933,7 +175393,7 @@ - + @@ -175311,6 +175771,15 @@ + + + + + + + + + @@ -177966,224 +178435,13 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -178278,17 +178536,6 @@ - - - - - - - - - - - @@ -178352,7 +178599,32 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -179698,7 +179970,7 @@ - + @@ -179727,7 +179999,7 @@ - + @@ -180319,7 +180591,7 @@ - + @@ -181279,7 +181551,7 @@ - + @@ -184237,6 +184509,21 @@ + + + + + + + + + + + + + + + diff --git a/android/abi_gki_aarch64_cuttlefish b/android/abi_gki_aarch64_cuttlefish index 12eb7ce410d0..c2732aa7dba0 100644 --- a/android/abi_gki_aarch64_cuttlefish +++ b/android/abi_gki_aarch64_cuttlefish @@ -10,6 +10,7 @@ arm64_const_caps_ready bcmp cancel_delayed_work_sync + cancel_work_sync capable cfg80211_inform_bss_data cfg80211_put_bss @@ -28,6 +29,7 @@ delayed_work_timer_fn destroy_workqueue _dev_err + device_create device_register device_unregister _dev_info @@ -39,6 +41,7 @@ dma_set_coherent_mask dma_set_mask down_write + ether_setup ethtool_op_get_link eth_validate_addr event_triggers_call @@ -60,6 +63,7 @@ init_wait_entry __init_waitqueue_head jiffies + jiffies_to_msecs kfree kfree_skb __kmalloc @@ -72,6 +76,8 @@ kmemdup kstrdup ktime_get + ktime_get_with_offset + kvfree __list_add_valid __list_del_entry_valid __local_bh_enable_ip @@ -83,6 +89,7 @@ __module_get module_layout module_put + __msecs_to_jiffies msleep __mutex_init mutex_lock @@ -98,6 +105,7 @@ netif_device_detach netif_tx_stop_all_queues netif_tx_wake_queue + nf_conntrack_destroy no_llseek nonseekable_open noop_llseek @@ -141,9 +149,8 @@ _raw_spin_unlock_irqrestore __rcu_read_lock __rcu_read_unlock - refcount_dec_and_test_checked - refcount_inc_checked - register_netdev + refcount_warn_saturate + register_netdevice register_netdevice_notifier register_virtio_device register_virtio_driver @@ -158,9 +165,12 @@ seq_printf sg_init_one sg_init_table + skb_add_rx_frag skb_clone skb_dequeue + skb_push skb_put + skb_queue_tail sk_free snd_device_new snd_pcm_alt_chmaps @@ -195,8 +205,11 @@ unregister_virtio_device unregister_virtio_driver up_write + virtio_break_device virtio_check_driver_offered_feature virtio_config_changed + virtio_device_freeze + virtio_device_restore virtio_max_dma_size virtqueue_add_inbuf virtqueue_add_outbuf @@ -270,10 +283,8 @@ hci_register_dev hci_unregister_dev skb_pull - skb_push skb_queue_head skb_queue_purge - skb_queue_tail # required by incrementalfs.ko bin2hex @@ -303,7 +314,6 @@ generic_file_read_iter generic_file_splice_read generic_read_dir - generic_shutdown_super __get_free_pages get_zeroed_page iget5_locked @@ -315,6 +325,7 @@ kernel_read kernel_write kern_path + kill_anon_super kobject_create_and_add kobject_put lockref_get @@ -323,7 +334,6 @@ LZ4_decompress_safe match_int match_token - __msecs_to_jiffies mutex_is_locked notify_change override_creds @@ -357,6 +367,76 @@ vfs_setxattr vfs_unlink +# required by mac80211_hwsim.ko + alloc_netdev_mqs + __cfg80211_alloc_event_skb + __cfg80211_alloc_reply_skb + __cfg80211_send_event_skb + cfg80211_vendor_cmd_reply + dev_alloc_name + device_bind_driver + device_release_driver + dst_release + eth_mac_addr + genlmsg_put + genl_notify + genl_register_family + genl_unregister_family + hrtimer_cancel + hrtimer_forward + hrtimer_init + hrtimer_start_range_ns + ieee80211_alloc_hw_nm + ieee80211_beacon_get_tim + ieee80211_csa_finish + ieee80211_csa_is_complete + ieee80211_free_hw + ieee80211_free_txskb + ieee80211_get_tx_rates + ieee80211_iterate_active_interfaces_atomic + ieee80211_probereq_get + ieee80211_queue_delayed_work + ieee80211_ready_on_channel + ieee80211_register_hw + ieee80211_remain_on_channel_expired + ieee80211_rx_irqsafe + ieee80211_scan_completed + ieee80211_start_tx_ba_cb_irqsafe + ieee80211_stop_tx_ba_cb_irqsafe + ieee80211_tx_prepare_skb + ieee80211_tx_status_irqsafe + ieee80211_unregister_hw + init_net + kstrndup + __netdev_alloc_skb + netif_rx + netlink_broadcast + netlink_register_notifier + netlink_unicast + netlink_unregister_notifier + net_namespace_list + nla_memcpy + __nla_parse + nla_put_64bit + nla_put + param_ops_ushort + ___ratelimit + register_pernet_device + regulatory_hint + rhashtable_destroy + rhashtable_init + rhashtable_insert_slow + __rht_bucket_nested + rht_bucket_nested + rht_bucket_nested_insert + schedule_timeout_interruptible + skb_copy + skb_copy_expand + __skb_ext_put + skb_trim + unregister_pernet_device + wiphy_apply_custom_regulatory + # required by nd_virtio.ko bio_alloc_bioset bio_chain @@ -380,6 +460,7 @@ netdev_lower_state_changed netdev_pick_tx pci_bus_type + register_netdev # required by rtc-test.ko add_timer @@ -466,7 +547,6 @@ idr_remove idr_replace __init_rwsem - jiffies_to_msecs jiffies_to_usecs krealloc memchr_inv @@ -501,11 +581,8 @@ cfg80211_scan_done __dev_get_by_index dev_printk - ether_setup - ktime_get_with_offset netdev_upper_dev_link netif_stacked_transfer_operstate - register_netdevice rtnl_link_register rtnl_link_unregister unregister_netdevice_many @@ -612,7 +689,6 @@ drm_universal_plane_init __get_task_comm kmalloc_order_trace - kvfree kvmalloc_node memdup_user mutex_trylock @@ -701,11 +777,9 @@ unregister_blkdev # required by virtio_console.ko - cancel_work_sync cdev_add cdev_alloc cdev_del - device_create device_destroy dma_alloc_attrs dma_free_attrs @@ -789,12 +863,10 @@ netif_set_real_num_tx_queues __netif_set_xps_queue net_ratelimit - nf_conntrack_destroy __num_online_cpus __pskb_pull_tail _raw_spin_trylock sched_clock - skb_add_rx_frag skb_coalesce_rx_frag __skb_flow_dissect skb_page_frag_refill @@ -820,6 +892,7 @@ # required by virtio_pci.ko irq_set_affinity_hint pci_alloc_irq_vectors_affinity + pci_device_is_present pci_find_capability pci_find_ext_capability pci_find_next_capability @@ -831,8 +904,6 @@ pci_release_region pci_release_selected_regions pci_request_selected_regions - virtio_device_freeze - virtio_device_restore # required by virtio_pmem.ko nvdimm_bus_register @@ -852,6 +923,7 @@ # required by vsock.ko autoremove_wake_function init_user_ns + mod_delayed_work_on ns_capable_noaudit prandom_u32 prepare_to_wait @@ -882,3 +954,8 @@ sock_diag_save_cookie sock_diag_unregister sock_i_ino + +# preserved by --additions-only + generic_shutdown_super + refcount_dec_and_test_checked + refcount_inc_checked diff --git a/drivers/clk/qcom/gcc-yupik.c b/drivers/clk/qcom/gcc-yupik.c index 696ec3760a24..622c52df92ad 100644 --- a/drivers/clk/qcom/gcc-yupik.c +++ b/drivers/clk/qcom/gcc-yupik.c @@ -2173,6 +2173,19 @@ static struct clk_branch gcc_pcie_clkref_en = { }, }; +static struct clk_branch gcc_edp_clkref_en = { + .halt_reg = 0x8c008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_edp_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_pcie_throttle_core_clk = { .halt_reg = 0x90018, .halt_check = BRANCH_HALT_SKIP, @@ -3510,6 +3523,7 @@ static struct clk_regmap *gcc_yupik_clocks[] = { [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, [GCC_VIDEO_MVP_THROTTLE_CORE_CLK] = &gcc_video_mvp_throttle_core_clk.clkr, + [GCC_EDP_CLKREF_EN] = &gcc_edp_clkref_en.clkr, }; static const struct qcom_reset_map gcc_yupik_resets[] = { diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index ac685b24144b..ec29d1d40c36 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __ADRENO_H #define __ADRENO_H @@ -16,9 +16,6 @@ #include "adreno_ringbuffer.h" #include "kgsl_sharedmem.h" -/* Index to preemption scratch buffer to store KMD postamble */ -#define KMD_POSTAMBLE_IDX 100 - /* ADRENO_DEVICE - Given a kgsl_device return the adreno device struct */ #define ADRENO_DEVICE(device) \ container_of(device, struct adreno_device, dev) diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index f0c5cf5a4869..cc5b11d30c4b 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include "adreno.h" @@ -553,8 +553,7 @@ unsigned int a6xx_preemption_pre_ibsubmit( /* Add a KMD post amble to clear the perf counters during preemption */ if (!adreno_dev->perfcounter) { - u64 kmd_postamble_addr = - PREEMPT_SCRATCH_ADDR(adreno_dev, KMD_POSTAMBLE_IDX); + u64 kmd_postamble_addr = SCRATCH_POSTAMBLE_ADDR(KGSL_DEVICE(adreno_dev)); *cmds++ = cp_type7_packet(CP_SET_AMBLE, 3); *cmds++ = lower_32_bits(kmd_postamble_addr); @@ -695,6 +694,7 @@ static int a6xx_preemption_ringbuffer_init(struct adreno_device *adreno_dev, int a6xx_preemption_init(struct adreno_device *adreno_dev) { + u32 flags = ADRENO_FEATURE(adreno_dev, ADRENO_APRIV) ? KGSL_MEMDESC_PRIVILEGED : 0; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); struct adreno_preemption *preempt = &adreno_dev->preempt; @@ -717,7 +717,7 @@ int a6xx_preemption_init(struct adreno_device *adreno_dev) if (IS_ERR_OR_NULL(preempt->scratch)) { preempt->scratch = kgsl_allocate_global(device, PAGE_SIZE, - 0, 0, 0, "preempt_scratch"); + 0, 0, flags, "preempt_scratch"); if (IS_ERR(preempt->scratch)) return PTR_ERR(preempt->scratch); } @@ -733,12 +733,13 @@ int a6xx_preemption_init(struct adreno_device *adreno_dev) return ret; /* - * First 8 dwords of the preemption scratch buffer is used to store the address for CP - * to save/restore VPC data. Reserve 11 dwords in the preemption scratch buffer from - * index KMD_POSTAMBLE_IDX for KMD postamble pm4 packets + * First 28 dwords of the device scratch buffer are used to store shadow rb data. + * Reserve 11 dwords in the device scratch buffer from SCRATCH_POSTAMBLE_OFFSET for + * KMD postamble pm4 packets. This should be in *device->scratch* so that userspace + * cannot access it. */ if (!adreno_dev->perfcounter) { - u32 *postamble = preempt->scratch->hostptr + (KMD_POSTAMBLE_IDX * sizeof(u64)); + u32 *postamble = device->scratch->hostptr + SCRATCH_POSTAMBLE_OFFSET; u32 count = 0; postamble[count++] = cp_type7_packet(CP_REG_RMW, 3); diff --git a/drivers/gpu/msm/adreno_hwsched.c b/drivers/gpu/msm/adreno_hwsched.c index 085c003e0bcd..6256b7adf086 100644 --- a/drivers/gpu/msm/adreno_hwsched.c +++ b/drivers/gpu/msm/adreno_hwsched.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "adreno.h" @@ -903,6 +904,23 @@ int adreno_hwsched_queue_cmds(struct kgsl_device_private *dev_priv, user_ts = *timestamp; + /* + * If there is only one drawobj in the array and it is of + * type SYNCOBJ_TYPE, skip comparing user_ts as it can be 0 + */ + if (!(count == 1 && drawobj[0]->type == SYNCOBJ_TYPE) && + (drawctxt->base.flags & KGSL_CONTEXT_USER_GENERATED_TS)) { + /* + * User specified timestamps need to be greater than the last + * issued timestamp in the context + */ + if (timestamp_cmp(drawctxt->timestamp, user_ts) >= 0) { + spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); + return -ERANGE; + } + } + for (i = 0; i < count; i++) { switch (drawobj[i]->type) { diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 69fdf288fa68..0f0721522574 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __KGSL_H #define __KGSL_H @@ -71,6 +72,11 @@ #define SCRATCH_RPTR_GPU_ADDR(dev, id) \ ((dev)->scratch->gpuaddr + SCRATCH_RPTR_OFFSET(id)) +/* OFFSET to KMD postamble packets in scratch buffer */ +#define SCRATCH_POSTAMBLE_OFFSET (100 * sizeof(u64)) +#define SCRATCH_POSTAMBLE_ADDR(dev) \ + ((dev)->scratch->gpuaddr + SCRATCH_POSTAMBLE_OFFSET) + /* Timestamp window used to detect rollovers (half of integer range) */ #define KGSL_TIMESTAMP_WINDOW 0x80000000 diff --git a/drivers/i2c/busses/i2c-msm-geni.c b/drivers/i2c/busses/i2c-msm-geni.c index 3a1964dfaac1..473ff18b0f2e 100644 --- a/drivers/i2c/busses/i2c-msm-geni.c +++ b/drivers/i2c/busses/i2c-msm-geni.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -136,10 +137,12 @@ struct geni_i2c_dev { bool disable_dma_mode; bool prev_cancel_pending; //Halt cancel till IOS in good state bool is_i2c_rtl_based; /* doing pending cancel only for rtl based SE's */ + atomic_t is_xfer_in_progress; /* Used to maintain xfer inprogress status */ }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; static int arr_idx; +static int geni_i2c_runtime_suspend(struct device *dev); struct geni_i2c_err_log { int err; @@ -1052,11 +1055,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; + atomic_set(&gi2c->is_xfer_in_progress, 1); /* Client to respect system suspend */ if (!pm_runtime_enabled(gi2c->dev)) { GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "%s: System suspended\n", __func__); + atomic_set(&gi2c->is_xfer_in_progress, 0); return -EACCES; } @@ -1068,6 +1073,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_put_noidle(gi2c->dev); /* Set device in suspended since resume failed */ pm_runtime_set_suspended(gi2c->dev); + atomic_set(&gi2c->is_xfer_in_progress, 0); return ret; } } @@ -1078,12 +1084,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, if (ret) { pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); + atomic_set(&gi2c->is_xfer_in_progress, 0); return ret; //Don't perform xfer is cancel failed } } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "n:%d addr:0x%x\n", num, msgs[0].addr); + "n:%d addr:0x%x\n", num, msgs[0].addr); gi2c->dbg_num = num; kfree(gi2c->dbg_buf_ptr); @@ -1268,7 +1275,7 @@ geni_i2c_txn_ret: pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); } - + atomic_set(&gi2c->is_xfer_in_progress, 0); gi2c->cur = NULL; GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c txn ret:%d, num:%d, err:%d\n", ret, num, gi2c->err); @@ -1476,10 +1483,10 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } + atomic_set(&gi2c->is_xfer_in_progress, 0); snprintf(boot_marker, sizeof(boot_marker), - "M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr); + "M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr); place_marker(boot_marker); - dev_info(gi2c->dev, "I2C probed\n"); return 0; } @@ -1489,6 +1496,33 @@ static int geni_i2c_remove(struct platform_device *pdev) struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); int i; + if (atomic_read(&gi2c->is_xfer_in_progress)) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s: Xfer is in progress\n", __func__); + return -EBUSY; + } + + if (!pm_runtime_status_suspended(gi2c->dev)) { + if (geni_i2c_runtime_suspend(gi2c->dev)) + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s: runtime suspend failed\n", __func__); + } + + if (gi2c->se_mode == GSI_ONLY) { + if (gi2c->tx_c) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s: clearing tx dma resource\n", __func__); + dma_release_channel(gi2c->tx_c); + } + if (gi2c->rx_c) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s: clearing rx dma resource\n", __func__); + dma_release_channel(gi2c->rx_c); + } + } + + pm_runtime_put_noidle(gi2c->dev); + pm_runtime_set_suspended(gi2c->dev); pm_runtime_disable(gi2c->dev); i2c_del_adapter(&gi2c->adap); @@ -1594,6 +1628,19 @@ static int geni_i2c_suspend_late(struct device *device) int ret; GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); + + if (atomic_read(&gi2c->is_xfer_in_progress)) { + if (!pm_runtime_status_suspended(gi2c->dev)) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + ":%s: runtime PM is active\n", __func__); + return -EBUSY; + } + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s System suspend not allowed while xfer in progress\n", + __func__); + return -EBUSY; + } + /* Make sure no transactions are pending */ ret = i2c_trylock_bus(&gi2c->adap, I2C_LOCK_SEGMENT); if (!ret) { diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9162bb4cc54c..789e433ac072 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -177,14 +177,25 @@ static void iommu_free_dev_param(struct device *dev) int iommu_probe_device(struct device *dev) { const struct iommu_ops *ops = dev->bus->iommu_ops; + static DEFINE_MUTEX(iommu_probe_device_lock); int ret; WARN_ON(dev->iommu_group); if (!ops) return -EINVAL; - if (!iommu_get_dev_param(dev)) - return -ENOMEM; + /* + * Serialise to avoid races between IOMMU drivers registering in + * parallel and/or the "replay" calls from ACPI/OF code via client + * driver probe. Once the latter have been cleaned up we should + * probably be able to use device_lock() here to minimise the scope, + * but for now enforcing a simple global ordering is fine. + */ + mutex_lock(&iommu_probe_device_lock); + if (!iommu_get_dev_param(dev)) { + ret = -ENOMEM; + goto err_unlock; + } if (!try_module_get(ops->owner)) { ret = -EINVAL; @@ -195,12 +206,17 @@ int iommu_probe_device(struct device *dev) if (ret) goto err_module_put; + mutex_unlock(&iommu_probe_device_lock); + return 0; err_module_put: module_put(ops->owner); err_free_dev_param: iommu_free_dev_param(dev); +err_unlock: + mutex_unlock(&iommu_probe_device_lock); + return ret; } diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index e58cb8434daf..12b7f698f562 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -800,6 +800,11 @@ static int dvb_demux_open(struct inode *inode, struct file *file) if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; + if (dmxdev->exit) { + mutex_unlock(&dmxdev->mutex); + return -ENODEV; + } + for (i = 0; i < dmxdev->filternum; i++) if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) break; @@ -1458,7 +1463,10 @@ EXPORT_SYMBOL(dvb_dmxdev_init); void dvb_dmxdev_release(struct dmxdev *dmxdev) { + mutex_lock(&dmxdev->mutex); dmxdev->exit = 1; + mutex_unlock(&dmxdev->mutex); + if (dmxdev->dvbdev->users > 1) { wait_event(dmxdev->dvbdev->wait_queue, dmxdev->dvbdev->users == 1); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9b7fb81fab52..f8abb3fa1f8f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -499,6 +499,7 @@ struct mac80211_hwsim_data { u32 ciphers[ARRAY_SIZE(hwsim_ciphers)]; struct mac_address addresses[2]; + struct ieee80211_chanctx_conf *chanctx; int channels, idx; bool use_chanctx; bool destroy_on_close; @@ -1059,6 +1060,47 @@ static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data, return res; } +static void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw, + const u8 *addr, bool add) +{ + struct mac80211_hwsim_data *data = hw->priv; + u32 _portid = READ_ONCE(data->wmediumd); + struct sk_buff *skb; + void *msg_head; + + if (!_portid && !hwsim_virtio_enabled) + return; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return; + + msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, + add ? HWSIM_CMD_ADD_MAC_ADDR : + HWSIM_CMD_DEL_MAC_ADDR); + if (!msg_head) { + pr_debug("mac80211_hwsim: problem with msg_head\n"); + goto nla_put_failure; + } + + if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, + ETH_ALEN, data->addresses[1].addr)) + goto nla_put_failure; + + if (nla_put(skb, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, addr)) + goto nla_put_failure; + + genlmsg_end(skb, msg_head); + + if (hwsim_virtio_enabled) + hwsim_tx_virtio(data, skb); + else + hwsim_unicast_netgroup(data, skb, _portid); + return; +nla_put_failure: + nlmsg_free(skb); +} + static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate) { u16 result = 0; @@ -1091,7 +1133,8 @@ static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate) static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, struct sk_buff *my_skb, - int dst_portid) + int dst_portid, + struct ieee80211_channel *channel) { struct sk_buff *skb; struct mac80211_hwsim_data *data = hw->priv; @@ -1146,7 +1189,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) goto nla_put_failure; - if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq)) + if (nla_put_u32(skb, HWSIM_ATTR_FREQ, channel->center_freq)) goto nla_put_failure; /* We get the tx control (rate and retries) info*/ @@ -1487,7 +1530,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, _portid = READ_ONCE(data->wmediumd); if (_portid || hwsim_virtio_enabled) - return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); + return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel); /* NO wmediumd detected, perfect medium simulation */ data->tx_pkts++; @@ -1540,6 +1583,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, vif->addr); hwsim_set_magic(vif); + if (vif->type != NL80211_IFTYPE_MONITOR) + mac80211_hwsim_config_mac_nl(hw, vif->addr, true); + vif->cab_queue = 0; vif->hw_queue[IEEE80211_AC_VO] = 0; vif->hw_queue[IEEE80211_AC_VI] = 1; @@ -1579,6 +1625,8 @@ static void mac80211_hwsim_remove_interface( vif->addr); hwsim_check_magic(vif); hwsim_clear_magic(vif); + if (vif->type != NL80211_IFTYPE_MONITOR) + mac80211_hwsim_config_mac_nl(hw, vif->addr, false); } static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, @@ -1598,7 +1646,7 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, mac80211_hwsim_monitor_rx(hw, skb, chan); if (_pid || hwsim_virtio_enabled) - return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); + return mac80211_hwsim_tx_frame_nl(hw, skb, _pid, chan); mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); dev_kfree_skb(skb); @@ -2092,6 +2140,8 @@ static void hw_scan_work(struct work_struct *work) hwsim->hw_scan_vif = NULL; hwsim->tmp_chan = NULL; mutex_unlock(&hwsim->mutex); + mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr, + false); return; } @@ -2177,6 +2227,7 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); mutex_unlock(&hwsim->mutex); + mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n"); ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); @@ -2220,6 +2271,7 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, pr_debug("hwsim sw_scan request, prepping stuff\n"); memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); + mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); hwsim->scanning = true; memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); @@ -2236,6 +2288,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw, pr_debug("hwsim sw_scan_complete\n"); hwsim->scanning = false; + mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false); eth_zero_addr(hwsim->scan_addr); mutex_unlock(&hwsim->mutex); @@ -2316,6 +2369,11 @@ static int mac80211_hwsim_croc(struct ieee80211_hw *hw, static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { + struct mac80211_hwsim_data *hwsim = hw->priv; + + mutex_lock(&hwsim->mutex); + hwsim->chanctx = ctx; + mutex_unlock(&hwsim->mutex); hwsim_set_chanctx_magic(ctx); wiphy_dbg(hw->wiphy, "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", @@ -2327,6 +2385,11 @@ static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { + struct mac80211_hwsim_data *hwsim = hw->priv; + + mutex_lock(&hwsim->mutex); + hwsim->chanctx = NULL; + mutex_unlock(&hwsim->mutex); wiphy_dbg(hw->wiphy, "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", ctx->def.chan->center_freq, ctx->def.width, @@ -2339,6 +2402,11 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { + struct mac80211_hwsim_data *hwsim = hw->priv; + + mutex_lock(&hwsim->mutex); + hwsim->chanctx = ctx; + mutex_unlock(&hwsim->mutex); hwsim_check_chanctx_magic(ctx); wiphy_dbg(hw->wiphy, "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", @@ -2926,6 +2994,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, hw->wiphy->max_remain_on_channel_duration = 1000; data->if_combination.radar_detect_widths = 0; data->if_combination.num_different_channels = data->channels; + data->chanctx = NULL; } else { data->if_combination.num_different_channels = 1; data->if_combination.radar_detect_widths = @@ -3420,6 +3489,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, int frame_data_len; void *frame_data; struct sk_buff *skb = NULL; + struct ieee80211_channel *channel = NULL; if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || !info->attrs[HWSIM_ATTR_FRAME] || @@ -3446,6 +3516,17 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, if (!data2) goto out; + if (data2->use_chanctx) { + if (data2->tmp_chan) + channel = data2->tmp_chan; + else if (data2->chanctx) + channel = data2->chanctx->def.chan; + } else { + channel = data2->channel; + } + if (!channel) + goto out; + if (!hwsim_virtio_enabled) { if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup) @@ -3457,7 +3538,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, /* check if radio is configured properly */ - if (data2->idle || !data2->started) + if ((data2->idle && !data2->tmp_chan) || !data2->started) goto out; /* A frame is received from user space */ @@ -3470,18 +3551,16 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, mutex_lock(&data2->mutex); rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]); - if (rx_status.freq != data2->channel->center_freq && - (!data2->tmp_chan || - rx_status.freq != data2->tmp_chan->center_freq)) { + if (rx_status.freq != channel->center_freq) { mutex_unlock(&data2->mutex); goto out; } mutex_unlock(&data2->mutex); } else { - rx_status.freq = data2->channel->center_freq; + rx_status.freq = channel->center_freq; } - rx_status.band = data2->channel->band; + rx_status.band = channel->band; rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) goto out; diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index 28ade92adcb4..9dceed77c5d6 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -75,6 +75,12 @@ enum hwsim_tx_control_flags { * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses: * %HWSIM_ATTR_RADIO_ID + * @HWSIM_CMD_ADD_MAC_ADDR: add a receive MAC address (given in the + * %HWSIM_ATTR_ADDR_RECEIVER attribute) to a device identified by + * %HWSIM_ATTR_ADDR_TRANSMITTER. This lets wmediumd forward frames + * to this receiver address for a given station. + * @HWSIM_CMD_DEL_MAC_ADDR: remove the MAC address again, the attributes + * are the same as to @HWSIM_CMD_ADD_MAC_ADDR. * @__HWSIM_CMD_MAX: enum limit */ enum { @@ -85,6 +91,8 @@ enum { HWSIM_CMD_NEW_RADIO, HWSIM_CMD_DEL_RADIO, HWSIM_CMD_GET_RADIO, + HWSIM_CMD_ADD_MAC_ADDR, + HWSIM_CMD_DEL_MAC_ADDR, __HWSIM_CMD_MAX, }; #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index ecd74be324fe..98d2ae6d8f16 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -168,6 +168,16 @@ config R8125 To compile this driver as a module, choose M here: the module will be called r8125. +config R8168 + tristate "Realtek R8168 driver" + depends on PCI + help + This is a 1Gbps ethernet driver for the PCI network cards based on + the Realtek RTL8111K chip. If you have one of those, say Y here. + + To compile this driver as a module, choose M here: the module + will be called r8168. + config R8125_IOSS tristate "Realtek R8125 IOSS glue driver" depends on R8125 diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index a966ba98c30a..da3d5d352cc1 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ /* @@ -631,8 +632,12 @@ static int spcom_handle_create_channel_command(void *cmd_buf, int cmd_size) mutex_lock(&spcom_dev->chdev_count_lock); ret = spcom_create_channel_chardev(cmd->ch_name, cmd->is_sharable); mutex_unlock(&spcom_dev->chdev_count_lock); - if (ret) - spcom_pr_err("failed to create ch[%s], ret [%d]\n", cmd->ch_name, ret); + if (ret) { + if (-EINVAL == ret) + spcom_pr_err("failed to create channel, ret [%d]\n", ret); + else + spcom_pr_err("failed to create ch[%s], ret [%d]\n", cmd->ch_name, ret); + } return ret; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f25bf76dafe3..a8caaab0eb52 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3277,7 +3277,13 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, * processed by the core. Hence do not reclaim it until * it is processed by the core. */ - if (req->trb->ctrl & DWC3_TRB_CTRL_HWO) { + /* + * If sg transfer are in progress, avoid checking + * HWO bit here as these will get cleared during + * ep reclaim. + */ + if ((req->trb->ctrl & DWC3_TRB_CTRL_HWO) + && (req->num_queued_sgs == 0)) { dbg_event(0xFF, "PEND TRB", dep->number); return 1; } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a6a31e624dcb..f94f44fcd311 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4706,9 +4706,17 @@ static int __ext4_get_inode_loc(struct inode *inode, inodes_per_block = EXT4_SB(sb)->s_inodes_per_block; inode_offset = ((inode->i_ino - 1) % EXT4_INODES_PER_GROUP(sb)); - block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block); iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb); + block = ext4_inode_table(sb, gdp); + if ((block <= le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) || + (block >= ext4_blocks_count(EXT4_SB(sb)->s_es))) { + ext4_error(sb, "Invalid inode table block %llu in " + "block_group %u", block, iloc->block_group); + return -EFSCORRUPTED; + } + block += (inode_offset / inodes_per_block); + bh = sb_getblk(sb, block); if (unlikely(!bh)) return -ENOMEM; diff --git a/include/dt-bindings/clock/qcom,gcc-yupik.h b/include/dt-bindings/clock/qcom,gcc-yupik.h index 5d1b744abbbf..190d9b7d1169 100644 --- a/include/dt-bindings/clock/qcom,gcc-yupik.h +++ b/include/dt-bindings/clock/qcom,gcc-yupik.h @@ -177,6 +177,7 @@ #define GCC_AGGRE_NOC_PCIE_CENTER_SF_AXI_CLK 167 #define GCC_AGGRE_NOC_PCIE_TBU_CLK 168 #define GCC_PCIE_CLKREF_EN 169 +#define GCC_EDP_CLKREF_EN 170 /* GCC power domains */ #define GCC_PCIE_0_GDSC 0 diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 8bef92bc3e8e..b46705a495aa 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -277,6 +277,13 @@ struct css_set { struct rcu_head rcu_head; }; +struct ext_css_set { + struct css_set cset; + + struct list_head mg_src_preload_node; + struct list_head mg_dst_preload_node; +}; + struct cgroup_base_stat { struct task_cputime cputime; }; diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 8a0e1bd77a4f..ff39d08cd175 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -70,7 +70,8 @@ struct css_task_iter { }; extern struct cgroup_root cgrp_dfl_root; -extern struct css_set init_css_set; +extern struct ext_css_set init_ext_css_set; +#define init_css_set init_ext_css_set.cset #define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; #include diff --git a/include/linux/mm.h b/include/linux/mm.h index de6db27e26b2..a54aca9bba65 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1542,6 +1542,12 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, #ifdef CONFIG_SPECULATIVE_PAGE_FAULT static inline void vm_write_begin(struct vm_area_struct *vma) { + /* + * Isolated vma might be freed without exclusive mmap_lock but + * speculative page fault handler still needs to know it was changed. + */ + if (!RB_EMPTY_NODE(&vma->vm_rb)) + WARN_ON_ONCE(!rwsem_is_locked(&(vma->vm_mm)->mmap_sem)); /* * The reads never spins and preemption * disablement is not required. diff --git a/include/uapi/linux/rmnet_ipa_fd_ioctl.h b/include/uapi/linux/rmnet_ipa_fd_ioctl.h index a8e40ef427b1..3ae29b4740e6 100644 --- a/include/uapi/linux/rmnet_ipa_fd_ioctl.h +++ b/include/uapi/linux/rmnet_ipa_fd_ioctl.h @@ -37,6 +37,7 @@ #define WAN_IOCTL_RMV_OFFLOAD_CONNECTION 19 #define WAN_IOCTL_GET_WAN_MTU 20 #define WAN_IOCTL_NOTIFY_NAT_MOVE_RES 21 +#define WAN_IOCTL_NOTIFY_DUAL_BACKHAUL_INFO 22 /* User space may not have this defined. */ #ifndef IFNAMSIZ @@ -195,6 +196,10 @@ struct wan_ioctl_query_per_client_stats { WAN_IOCTL_ADD_FLT_RULE, \ struct ipa_install_fltr_rule_req_msg_v01 *) +#define WAN_IOC_NOTIFY_DUAL_BACKHAUL_INFO _IOWR(WAN_IOC_MAGIC, \ + WAN_IOCTL_NOTIFY_DUAL_BACKHAUL_INFO, \ + struct ipa_eth_backhaul_info_req_msg_v01 *) + #define WAN_IOC_ADD_FLT_RULE_INDEX _IOWR(WAN_IOC_MAGIC, \ WAN_IOCTL_ADD_FLT_INDEX, \ struct ipa_fltr_installed_notif_req_msg_v01 *) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index a6df9e6f4b52..a3f9fab44993 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -751,25 +751,28 @@ EXPORT_SYMBOL_GPL(of_css); * reference-counted, to improve performance when child cgroups * haven't been created. */ -struct css_set init_css_set = { - .refcount = REFCOUNT_INIT(1), - .dom_cset = &init_css_set, - .tasks = LIST_HEAD_INIT(init_css_set.tasks), - .mg_tasks = LIST_HEAD_INIT(init_css_set.mg_tasks), - .dying_tasks = LIST_HEAD_INIT(init_css_set.dying_tasks), - .task_iters = LIST_HEAD_INIT(init_css_set.task_iters), - .threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets), - .cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links), - .mg_preload_node = LIST_HEAD_INIT(init_css_set.mg_preload_node), - .mg_node = LIST_HEAD_INIT(init_css_set.mg_node), - - /* - * The following field is re-initialized when this cset gets linked - * in cgroup_init(). However, let's initialize the field - * statically too so that the default cgroup can be accessed safely - * early during boot. - */ - .dfl_cgrp = &cgrp_dfl_root.cgrp, +struct ext_css_set init_ext_css_set = { + .cset = { + .refcount = REFCOUNT_INIT(1), + .dom_cset = &init_css_set, + .tasks = LIST_HEAD_INIT(init_css_set.tasks), + .mg_tasks = LIST_HEAD_INIT(init_css_set.mg_tasks), + .dying_tasks = LIST_HEAD_INIT(init_css_set.dying_tasks), + .task_iters = LIST_HEAD_INIT(init_css_set.task_iters), + .threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets), + .cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links), + .mg_preload_node = LIST_HEAD_INIT(init_css_set.mg_preload_node), + .mg_node = LIST_HEAD_INIT(init_css_set.mg_node), + /* + * The following field is re-initialized when this cset gets linked + * in cgroup_init(). However, let's initialize the field + * statically too so that the default cgroup can be accessed safely + * early during boot. + */ + .dfl_cgrp = &cgrp_dfl_root.cgrp, + }, + .mg_src_preload_node = LIST_HEAD_INIT(init_ext_css_set.mg_src_preload_node), + .mg_dst_preload_node = LIST_HEAD_INIT(init_ext_css_set.mg_dst_preload_node), }; static int css_set_count = 1; /* 1 for init_css_set */ @@ -1197,6 +1200,7 @@ static struct css_set *find_css_set(struct css_set *old_cset, struct cgroup *cgrp) { struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT] = { }; + struct ext_css_set *ext_cset; struct css_set *cset; struct list_head tmp_links; struct cgrp_cset_link *link; @@ -1217,9 +1221,10 @@ static struct css_set *find_css_set(struct css_set *old_cset, if (cset) return cset; - cset = kzalloc(sizeof(*cset), GFP_KERNEL); - if (!cset) + ext_cset = kzalloc(sizeof(*ext_cset), GFP_KERNEL); + if (!ext_cset) return NULL; + cset = &ext_cset->cset; /* Allocate all the cgrp_cset_link objects that we'll need */ if (allocate_cgrp_cset_links(cgroup_root_count, &tmp_links) < 0) { @@ -1237,6 +1242,8 @@ static struct css_set *find_css_set(struct css_set *old_cset, INIT_HLIST_NODE(&cset->hlist); INIT_LIST_HEAD(&cset->cgrp_links); INIT_LIST_HEAD(&cset->mg_preload_node); + INIT_LIST_HEAD(&ext_cset->mg_src_preload_node); + INIT_LIST_HEAD(&ext_cset->mg_dst_preload_node); INIT_LIST_HEAD(&cset->mg_node); /* Copy the set of subsystem state objects generated in @@ -2687,22 +2694,28 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp) */ void cgroup_migrate_finish(struct cgroup_mgctx *mgctx) { - LIST_HEAD(preloaded); - struct css_set *cset, *tmp_cset; + struct ext_css_set *cset, *tmp_cset; lockdep_assert_held(&cgroup_mutex); spin_lock_irq(&css_set_lock); - list_splice_tail_init(&mgctx->preloaded_src_csets, &preloaded); - list_splice_tail_init(&mgctx->preloaded_dst_csets, &preloaded); + list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets, + mg_src_preload_node) { + cset->cset.mg_src_cgrp = NULL; + cset->cset.mg_dst_cgrp = NULL; + cset->cset.mg_dst_cset = NULL; + list_del_init(&cset->mg_src_preload_node); + put_css_set_locked(&cset->cset); + } - list_for_each_entry_safe(cset, tmp_cset, &preloaded, mg_preload_node) { - cset->mg_src_cgrp = NULL; - cset->mg_dst_cgrp = NULL; - cset->mg_dst_cset = NULL; - list_del_init(&cset->mg_preload_node); - put_css_set_locked(cset); + list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets, + mg_dst_preload_node) { + cset->cset.mg_src_cgrp = NULL; + cset->cset.mg_dst_cgrp = NULL; + cset->cset.mg_dst_cset = NULL; + list_del_init(&cset->mg_dst_preload_node); + put_css_set_locked(&cset->cset); } spin_unlock_irq(&css_set_lock); @@ -2729,6 +2742,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset, struct cgroup_mgctx *mgctx) { struct cgroup *src_cgrp; + struct ext_css_set *ext_src_cset; lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&css_set_lock); @@ -2742,8 +2756,9 @@ void cgroup_migrate_add_src(struct css_set *src_cset, return; src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root); + ext_src_cset = container_of(src_cset, struct ext_css_set, cset); - if (!list_empty(&src_cset->mg_preload_node)) + if (!list_empty(&ext_src_cset->mg_src_preload_node)) return; WARN_ON(src_cset->mg_src_cgrp); @@ -2754,7 +2769,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset, src_cset->mg_src_cgrp = src_cgrp; src_cset->mg_dst_cgrp = dst_cgrp; get_css_set(src_cset); - list_add_tail(&src_cset->mg_preload_node, &mgctx->preloaded_src_csets); + list_add_tail(&ext_src_cset->mg_src_preload_node, &mgctx->preloaded_src_csets); } /** @@ -2773,20 +2788,23 @@ void cgroup_migrate_add_src(struct css_set *src_cset, */ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx) { - struct css_set *src_cset, *tmp_cset; + struct ext_css_set *ext_src_set, *tmp_cset; lockdep_assert_held(&cgroup_mutex); /* look up the dst cset for each src cset and link it to src */ - list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets, - mg_preload_node) { + list_for_each_entry_safe(ext_src_set, tmp_cset, &mgctx->preloaded_src_csets, + mg_src_preload_node) { + struct css_set *src_cset = &ext_src_set->cset; struct css_set *dst_cset; + struct ext_css_set *ext_dst_cset; struct cgroup_subsys *ss; int ssid; dst_cset = find_css_set(src_cset, src_cset->mg_dst_cgrp); if (!dst_cset) return -ENOMEM; + ext_dst_cset = container_of(dst_cset, struct ext_css_set, cset); WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset); @@ -2798,7 +2816,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx) if (src_cset == dst_cset) { src_cset->mg_src_cgrp = NULL; src_cset->mg_dst_cgrp = NULL; - list_del_init(&src_cset->mg_preload_node); + list_del_init(&ext_src_set->mg_src_preload_node); put_css_set(src_cset); put_css_set(dst_cset); continue; @@ -2806,8 +2824,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx) src_cset->mg_dst_cset = dst_cset; - if (list_empty(&dst_cset->mg_preload_node)) - list_add_tail(&dst_cset->mg_preload_node, + if (list_empty(&ext_dst_cset->mg_dst_preload_node)) + list_add_tail(&ext_dst_cset->mg_dst_preload_node, &mgctx->preloaded_dst_csets); else put_css_set(dst_cset); @@ -3026,8 +3044,8 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) DEFINE_CGROUP_MGCTX(mgctx); struct cgroup_subsys_state *d_css; struct cgroup *dsct; - struct css_set *src_cset; bool has_tasks; + struct ext_css_set *ext_src_set; int ret; lockdep_assert_held(&cgroup_mutex); @@ -3057,11 +3075,12 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) goto out_finish; spin_lock_irq(&css_set_lock); - list_for_each_entry(src_cset, &mgctx.preloaded_src_csets, mg_preload_node) { + list_for_each_entry(ext_src_set, &mgctx.preloaded_src_csets, + mg_src_preload_node) { struct task_struct *task, *ntask; /* all tasks in src_csets need to be migrated */ - list_for_each_entry_safe(task, ntask, &src_cset->tasks, cg_list) + list_for_each_entry_safe(task, ntask, &ext_src_set->cset.tasks, cg_list) cgroup_migrate_add_task(task, &mgctx); } spin_unlock_irq(&css_set_lock); diff --git a/mm/filemap.c b/mm/filemap.c index bf097b21ce0b..a7a79261d008 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2495,7 +2495,9 @@ static struct file *do_async_mmap_readahead(struct vm_fault *vmf, * it in the page cache, and handles the special cases reasonably without * having a lot of duplicated code. * - * vma->vm_mm->mmap_sem must be held on entry (except FAULT_FLAG_SPECULATIVE). + * If FAULT_FLAG_SPECULATIVE is set, this function runs with elevated vma + * refcount and with mmap lock not held. + * Otherwise, vma->vm_mm->mmap_sem must be held on entry. * * If our return value has VM_FAULT_RETRY set, it's because the mmap_sem * may be dropped before doing I/O or by lock_page_maybe_drop_mmap(). @@ -2520,6 +2522,52 @@ vm_fault_t filemap_fault(struct vm_fault *vmf) struct page *page; vm_fault_t ret = 0; + if (vmf->flags & FAULT_FLAG_SPECULATIVE) { + page = find_get_page(mapping, offset); + if (unlikely(!page)) + return VM_FAULT_RETRY; + + if (unlikely(PageReadahead(page))) + goto page_put; + + if (!trylock_page(page)) + goto page_put; + + if (unlikely(compound_head(page)->mapping != mapping)) + goto page_unlock; + VM_BUG_ON_PAGE(page_to_pgoff(page) != offset, page); + if (unlikely(!PageUptodate(page))) + goto page_unlock; + + max_off = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); + if (unlikely(offset >= max_off)) + goto page_unlock; + + /* + * Update readahead mmap_miss statistic. + * + * Note that we are not sure if finish_fault() will + * manage to complete the transaction. If it fails, + * we'll come back to filemap_fault() non-speculative + * case which will update mmap_miss a second time. + * This is not ideal, we would prefer to guarantee the + * update will happen exactly once. + */ + if (!(vmf->vma->vm_flags & VM_RAND_READ) && ra->ra_pages) { + unsigned int mmap_miss = READ_ONCE(ra->mmap_miss); + if (mmap_miss) + WRITE_ONCE(ra->mmap_miss, --mmap_miss); + } + + vmf->page = page; + return VM_FAULT_LOCKED; +page_unlock: + unlock_page(page); +page_put: + put_page(page); + return VM_FAULT_RETRY; + } + max_off = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); if (unlikely(offset >= max_off)) return VM_FAULT_SIGBUS; diff --git a/mm/khugepaged.c b/mm/khugepaged.c index bd034e57b11e..2aa19037c4ab 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -1343,6 +1343,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr) if (!pmd) goto drop_hpage; + vm_write_begin(vma); start_pte = pte_offset_map_lock(mm, pmd, haddr, &ptl); /* step 1: check all mapped PTEs are to the right huge page */ @@ -1392,6 +1393,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr) ptl = pmd_lock(vma->vm_mm, pmd); _pmd = pmdp_collapse_flush(vma, haddr, pmd); spin_unlock(ptl); + vm_write_end(vma); mm_dec_nr_ptes(mm); pte_free(mm, pmd_pgtable(_pmd)); @@ -1402,6 +1404,7 @@ drop_hpage: abort: pte_unmap_unlock(start_pte, ptl); + vm_write_end(vma); goto drop_hpage; } @@ -1473,10 +1476,12 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff) */ if (down_write_trylock(&mm->mmap_sem)) { if (!khugepaged_test_exit(mm)) { + vm_write_begin(vma); spinlock_t *ptl = pmd_lock(mm, pmd); /* assume page table is clear */ _pmd = pmdp_collapse_flush(vma, addr, pmd); spin_unlock(ptl); + vm_write_end(vma); mm_dec_nr_ptes(mm); pte_free(mm, pmd_pgtable(_pmd)); } diff --git a/mm/madvise.c b/mm/madvise.c index 5f38b9faeb27..c87d4c43b885 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -500,11 +500,9 @@ static void madvise_cold_page_range(struct mmu_gather *tlb, .target_task = task, }; - vm_write_begin(vma); tlb_start_vma(tlb, vma); walk_page_range(vma->vm_mm, addr, end, &cold_walk_ops, &walk_private); tlb_end_vma(tlb, vma); - vm_write_end(vma); } static long madvise_cold(struct task_struct *task, @@ -538,11 +536,9 @@ static void madvise_pageout_page_range(struct mmu_gather *tlb, .target_task = task, }; - vm_write_begin(vma); tlb_start_vma(tlb, vma); walk_page_range(vma->vm_mm, addr, end, &cold_walk_ops, &walk_private); tlb_end_vma(tlb, vma); - vm_write_end(vma); } static inline bool can_do_pageout(struct vm_area_struct *vma) @@ -745,12 +741,10 @@ static int madvise_free_single_vma(struct vm_area_struct *vma, update_hiwater_rss(mm); mmu_notifier_invalidate_range_start(&range); - vm_write_begin(vma); tlb_start_vma(&tlb, vma); walk_page_range(vma->vm_mm, range.start, range.end, &madvise_free_walk_ops, &tlb); tlb_end_vma(&tlb, vma); - vm_write_end(vma); mmu_notifier_invalidate_range_end(&range); tlb_finish_mmu(&tlb, range.start, range.end); diff --git a/mm/memory.c b/mm/memory.c index 159418393187..47c12f886c0d 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1292,7 +1292,6 @@ void unmap_page_range(struct mmu_gather *tlb, unsigned long next; BUG_ON(addr >= end); - vm_write_begin(vma); tlb_start_vma(tlb, vma); pgd = pgd_offset(vma->vm_mm, addr); do { @@ -1302,7 +1301,6 @@ void unmap_page_range(struct mmu_gather *tlb, next = zap_p4d_range(tlb, vma, pgd, addr, next, details); } while (pgd++, addr = next, addr != end); tlb_end_vma(tlb, vma); - vm_write_end(vma); } @@ -3050,6 +3048,11 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) int exclusive = 0; vm_fault_t ret; + if (vmf->flags & FAULT_FLAG_SPECULATIVE) { + pte_unmap(vmf->pte); + return VM_FAULT_RETRY; + } + ret = pte_unmap_same(vmf); if (ret) { /* @@ -3296,6 +3299,10 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf) if (vmf->vma_flags & VM_SHARED) return VM_FAULT_SIGBUS; + /* Do not check unstable pmd, if it's changed will retry later */ + if (vmf->flags & FAULT_FLAG_SPECULATIVE) + goto skip_pmd_checks; + /* * Use pte_alloc() instead of pte_alloc_map(). We can't run * pte_offset_map() on pmds where a huge pmd might be created @@ -3313,6 +3320,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf) if (unlikely(pmd_trans_unstable(vmf->pmd))) return 0; +skip_pmd_checks: /* Use the zero-page for reads */ if (!(vmf->flags & FAULT_FLAG_WRITE) && !mm_forbids_zeropage(vma->vm_mm)) { @@ -3417,6 +3425,10 @@ static vm_fault_t __do_fault(struct vm_fault *vmf) struct vm_area_struct *vma = vmf->vma; vm_fault_t ret; + /* Do not check unstable pmd, if it's changed will retry later */ + if (vmf->flags & FAULT_FLAG_SPECULATIVE) + goto skip_pmd_checks; + /* * Preallocate pte before we take page_lock because this might lead to * deadlocks for memcg reclaim which waits for pages under writeback: @@ -3439,6 +3451,7 @@ static vm_fault_t __do_fault(struct vm_fault *vmf) smp_wmb(); /* See comment in __pte_alloc() */ } +skip_pmd_checks: ret = vma->vm_ops->fault(vmf); if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY | VM_FAULT_DONE_COW))) @@ -3812,7 +3825,8 @@ static vm_fault_t do_fault_around(struct vm_fault *vmf) end_pgoff = min3(end_pgoff, vma_pages(vmf->vma) + vmf->vma->vm_pgoff - 1, start_pgoff + nr_pages - 1); - if (pmd_none(*vmf->pmd)) { + if (!(vmf->flags & FAULT_FLAG_SPECULATIVE) && + pmd_none(*vmf->pmd)) { vmf->prealloc_pte = pte_alloc_one(vmf->vma->vm_mm); if (!vmf->prealloc_pte) goto out; @@ -4179,16 +4193,11 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) pte_t entry; vm_fault_t ret = 0; + /* Do not check unstable pmd, if it's changed will retry later */ + if (vmf->flags & FAULT_FLAG_SPECULATIVE) + goto skip_pmd_checks; + if (unlikely(pmd_none(*vmf->pmd))) { - /* - * In the case of the speculative page fault handler we abort - * the speculative path immediately as the pmd is probably - * in the way to be converted in a huge one. We will try - * again holding the mmap_sem (which implies that the collapse - * operation is done). - */ - if (vmf->flags & FAULT_FLAG_SPECULATIVE) - return VM_FAULT_RETRY; /* * Leave __pte_alloc() until later: because vm_ops->fault may * want to allocate huge page, and if we expose page table @@ -4196,8 +4205,7 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) * concurrent faults and from rmap lookups. */ vmf->pte = NULL; - } else if (!(vmf->flags & FAULT_FLAG_SPECULATIVE)) { - /* See comment in pte_alloc_one_map() */ + } else { if (pmd_devmap_trans_unstable(vmf->pmd)) return 0; /* @@ -4227,6 +4235,7 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) } } +skip_pmd_checks: if (!vmf->pte) { if (vma_is_anonymous(vmf->vma)) return do_anonymous_page(vmf); @@ -4465,9 +4474,8 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address, pol = __get_vma_policy(vmf.vma, address); if (!pol) pol = get_task_policy(current); - if (!pol) - if (pol && pol->mode == MPOL_INTERLEAVE) - return VM_FAULT_RETRY; + if (pol && pol->mode == MPOL_INTERLEAVE) + return VM_FAULT_RETRY; #endif /* diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 85b97f3471f4..54dd6c5bb913 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -599,11 +599,9 @@ unsigned long change_prot_numa(struct vm_area_struct *vma, { int nr_updated; - vm_write_begin(vma); nr_updated = change_protection(vma, addr, end, PAGE_NONE, 0, 1); if (nr_updated) count_vm_numa_events(NUMA_PTE_UPDATES, nr_updated); - vm_write_end(vma); return nr_updated; } diff --git a/mm/mmap.c b/mm/mmap.c index 24fb2d87142d..56ba432e7f1f 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2344,8 +2344,22 @@ struct vm_area_struct *get_vma(struct mm_struct *mm, unsigned long addr) read_lock(&mm->mm_rb_lock); vma = __find_vma(mm, addr); - if (vma) - atomic_inc(&vma->vm_ref_count); + + /* + * If there is a concurrent fast mremap, bail out since the entire + * PMD/PUD subtree may have been remapped. + * + * This is usually safe for conventional mremap since it takes the + * PTE locks as does SPF. However fast mremap only takes the lock + * at the PMD/PUD level which is ok as it is done with the mmap + * write lock held. But since SPF, as the term implies forgoes, + * taking the mmap read lock and also cannot take PTL lock at the + * larger PMD/PUD granualrity, since it would introduce huge + * contention in the page fault path; fall back to regular fault + * handling. + */ + if (vma && !atomic_inc_unless_negative(&vma->vm_ref_count)) + vma = NULL; read_unlock(&mm->mm_rb_lock); return vma; diff --git a/mm/mremap.c b/mm/mremap.c index f7c278e65a5d..559255d32273 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -191,6 +191,38 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, drop_rmap_locks(vma); } +#ifdef CONFIG_SPECULATIVE_PAGE_FAULT +static inline bool trylock_vma_ref_count(struct vm_area_struct *vma) +{ + /* + * If we have the only reference, swap the refcount to -1. This + * will prevent other concurrent references by get_vma() for SPFs. + */ + return atomic_cmpxchg(&vma->vm_ref_count, 1, -1) == 1; +} + +/* + * Restore the VMA reference count to 1 after a fast mremap. + */ +static inline void unlock_vma_ref_count(struct vm_area_struct *vma) +{ + /* + * This should only be called after a corresponding, + * successful trylock_vma_ref_count(). + */ + VM_BUG_ON_VMA(atomic_cmpxchg(&vma->vm_ref_count, -1, 1) != -1, + vma); +} +#else /* !CONFIG_SPECULATIVE_PAGE_FAULT */ +static inline bool trylock_vma_ref_count(struct vm_area_struct *vma) +{ + return true; +} +static inline void unlock_vma_ref_count(struct vm_area_struct *vma) +{ +} +#endif /* CONFIG_SPECULATIVE_PAGE_FAULT */ + #ifdef CONFIG_HAVE_MOVE_PMD static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr, unsigned long new_addr, unsigned long old_end, @@ -211,6 +243,14 @@ static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr, if (WARN_ON(!pmd_none(*new_pmd))) return false; + /* + * We hold both exclusive mmap_lock and rmap_lock at this point and + * cannot block. If we cannot immediately take exclusive ownership + * of the VMA fallback to the move_ptes(). + */ + if (!trylock_vma_ref_count(vma)) + return false; + /* * We don't have to worry about the ordering of src and dst * ptlocks because exclusive mmap_sem prevents deadlock. @@ -233,6 +273,7 @@ static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr, spin_unlock(new_ptl); spin_unlock(old_ptl); + unlock_vma_ref_count(vma); return true; } #endif diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 4a6396d574a0..fd4da1019e44 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1137,14 +1137,16 @@ static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu, dev->needed_headroom = dst_len; if (set_mtu) { - dev->mtu = rt->dst.dev->mtu - t_hlen; - if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) - dev->mtu -= 8; - if (dev->type == ARPHRD_ETHER) - dev->mtu -= ETH_HLEN; + int mtu = rt->dst.dev->mtu - t_hlen; - if (dev->mtu < IPV6_MIN_MTU) - dev->mtu = IPV6_MIN_MTU; + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + mtu -= 8; + if (dev->type == ARPHRD_ETHER) + mtu -= ETH_HLEN; + + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + WRITE_ONCE(dev->mtu, mtu); } } ip6_rt_put(rt); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 878a08c40fff..acc75975edde 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1430,6 +1430,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) struct __ip6_tnl_parm *p = &t->parms; struct flowi6 *fl6 = &t->fl.u.ip6; int t_hlen; + int mtu; memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); @@ -1472,12 +1473,13 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) dev->hard_header_len = rt->dst.dev->hard_header_len + t_hlen; - dev->mtu = rt->dst.dev->mtu - t_hlen; + mtu = rt->dst.dev->mtu - t_hlen; if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) - dev->mtu -= 8; + mtu -= 8; - if (dev->mtu < IPV6_MIN_MTU) - dev->mtu = IPV6_MIN_MTU; + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + WRITE_ONCE(dev->mtu, mtu); } ip6_rt_put(rt); } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 117d374695fe..1179608955f5 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1083,10 +1083,12 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) if (tdev && !netif_is_l3_master(tdev)) { int t_hlen = tunnel->hlen + sizeof(struct iphdr); + int mtu; - dev->mtu = tdev->mtu - t_hlen; - if (dev->mtu < IPV6_MIN_MTU) - dev->mtu = IPV6_MIN_MTU; + mtu = tdev->mtu - t_hlen; + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + WRITE_ONCE(dev->mtu, mtu); } } diff --git a/net/sched/ematch.c b/net/sched/ematch.c index dd3b8c11a2e0..43bfb33629e9 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -255,6 +255,8 @@ static int tcf_em_validate(struct tcf_proto *tp, * the value carried. */ if (em_hdr->flags & TCF_EM_SIMPLE) { + if (em->ops->datalen > 0) + goto errout; if (data_len < sizeof(u32)) goto errout; em->data = *(u32 *) data;