mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 02:21:52 +09:00
Merge branch 'android14-6.1' into android14-6.1-lts
Catch the -lts branch up with what is in the normal branch. Changes in here are: *1c9aeb1ce3Merge tag 'android14-6.1.129_r00' into android14-6.1 *b18db21117ANDROID: GKI: Update rockchip symbols for drm driver. *f628136006ANDROID: ABI: Update pixel symbol list *2fb96ec85cANDROID: vendor_hook: add vendor hook on calculate_totalreserve_pages *5145d15773ANDROID: GKI: update symbol list file for xiaomi *2f4537ba6cANDROID: vendor_hooks: Skip pages with high memory pressure in shrink_active_list *da6a42c111FROMGIT: mm/page_alloc: add trace event for totalreserve_pages calculation *95baed1663BACKPORT: FROMGIT: mm/page_alloc: add trace event for per-zone lowmem reserve setup *9d6305174cBACKPORT: FROMGIT: mm/page_alloc: add trace event for per-zone watermark setup *7da329f7cfANDROID: Update the ABI symbol list *d3b0aaa092ANDROID: Add EXPORT_SYMBOL_GPL for folio_mapcount *6bd3e435f2UPSTREAM: f2fs: fix inconsistent dirty state of atomic file *2afd0800a7UPSTREAM: net: avoid race between device unregistration and ethnl ops *92ada4b4c2UPSTREAM: pfifo_tail_enqueue: Drop new packet when sch->limit == 0 *cd0ebcd175UPSTREAM: vsock: Orphan socket after transport release *7f11cc02d9UPSTREAM: vsock: Keep the binding until socket destruction *e2647b0fb4UPSTREAM: bpf, vsock: Invoke proto::close on close() *cfa792a776FROMGIT: f2fs: fix to avoid atomicity corruption of atomic file *f3c4686f77ANDROID: abi_gki_aarch64_qcom: Add xas_load *33c9d4844aANDROID: Update the ABI symbol list *0ad7fae66cANDROID: printk: add vendor hook to logging during hibernation *4da91a8e56BACKPORT: FROMGIT: f2fs: fix to avoid running out of free segments *64560e780eBACKPORT: FROMGIT: f2fs: fix to avoid panic once fallocation fails for pinfile *27895588a2BACKPORT: f2fs: compress: fix inconsistent update of i_blocks in release_compress_blocks and reserve_compress_blocks *70d032fba5ANDROID: GKI: Add KMI symbol list for zebra *efd0bedd2cANDROID: GKI: Update rockchip symbols for drm driver. *69a6dfc9c3ANDROID: GKI: Update symbol list for mtk *9bcabbda67ANDROID: userfaultfd: add MOVE ioctl mode to confirm bug-fixes *8d8d44ff91FROMGIT: userfaultfd: fix PTE unmapping stack-allocated PTE copies *af439accc7FROMGIT: userfaultfd: do not block on locking a large folio with raised refcount *7d6124b604FROMGIT: BACKPORT: mm: fix kernel BUG when userfaultfd_move encounters swapcache *44db4837f7ANDROID: Update the ABI symbol list *50eddb3fc9FROMGIT: f2fs: set highest IO priority for checkpoint thread *471a10d3afANDROID: mm/memfd-ashmem-shim: Fix variable length array usage *6b227a1f74ANDROID: GKI: Update symbol list for xiaomi *eaffa3e341ANDROID: mm: add a new vendor hook in filemap_map_pages *fa3cc11118ANDROID: GKI: Enable CONFIG_MEMFD_ASHMEM_SHIM *6355ece3caANDROID: mm: shmem: Use memfd-ashmem-shim ioctl handler *004c31328aANDROID: mm/memfd-ashmem-shim: Introduce shim layer *b4fef39187ANDROID: ashmem: Add toggle to ignore requests to deny PROT_EXEC mappings *ef10c0ef7dANDROID: ashmem: Add toggle to ignore requests to deny PROT_READ mappings *9f6b96dfcaANDROID: ashmem: Add support for disabling unpinning feature *4deb2cd703ANDROID: Update the ABI symbol list *75c1d11b88ANDROID: swapfile: Add EXPORT_SYMBOL_GPL for page_swap_info *f27efe75fcUPSTREAM: io_uring: fix io_req_prep_async with provided buffers *719cffaab0ANDROID: GKI: Update symbol list for BCMSTB *6ad8aa12e1ANDROID: abi_gki_aarch64_qcom: Update symbol list *45755ee7b6ANDROID: of: add export symbol for of_update_property *cf7683f719ANDROID: GKI: Update oplus symbol list Change-Id: I8da40828d5179139546e9bc8b15efdbae9bc57de Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -131,6 +131,7 @@ filegroup(
|
||||
"android/abi_gki_aarch64_virtual_device",
|
||||
"android/abi_gki_aarch64_vivo",
|
||||
"android/abi_gki_aarch64_xiaomi",
|
||||
"android/abi_gki_aarch64_zebra",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -406,6 +406,7 @@
|
||||
phy_ethtool_nway_reset
|
||||
phy_ethtool_set_eee
|
||||
phy_ethtool_set_link_ksettings
|
||||
phy_ethtool_set_wol
|
||||
phy_exit
|
||||
phy_init
|
||||
phy_init_eee
|
||||
@@ -801,6 +802,9 @@
|
||||
# required by bcm7038_wdt.ko
|
||||
devm_watchdog_register_device
|
||||
|
||||
# required by bcm74110-rng.ko
|
||||
devm_hwrng_register
|
||||
|
||||
# required by bcm7xxx.ko
|
||||
genphy_restart_aneg
|
||||
|
||||
@@ -865,23 +869,6 @@
|
||||
of_find_net_device_by_node
|
||||
of_find_node_by_phandle
|
||||
|
||||
# required by brcmstb-iommu.ko
|
||||
devm_get_free_pages
|
||||
generic_device_group
|
||||
iommu_device_register
|
||||
iommu_device_sysfs_add
|
||||
iommu_device_sysfs_remove
|
||||
iommu_device_unlink
|
||||
iommu_device_unregister
|
||||
iommu_fwspec_init
|
||||
iommu_group_alloc
|
||||
iommu_group_put
|
||||
iommu_group_ref_get
|
||||
iommu_group_set_name
|
||||
pci_device_group
|
||||
pci_find_host_bridge
|
||||
platform_get_irq_byname
|
||||
|
||||
# required by brcmstb-proc-info.ko
|
||||
find_get_pid
|
||||
generic_file_open
|
||||
@@ -899,6 +886,21 @@
|
||||
# required by brcmstb_gisb.ko
|
||||
__sw_hweight64
|
||||
|
||||
# required by brcmstb_iommu.ko
|
||||
devm_get_free_pages
|
||||
iommu_device_register
|
||||
iommu_device_sysfs_add
|
||||
iommu_device_sysfs_remove
|
||||
iommu_device_unlink
|
||||
iommu_device_unregister
|
||||
iommu_fwspec_init
|
||||
iommu_group_alloc
|
||||
iommu_group_put
|
||||
iommu_group_ref_get
|
||||
pci_device_group
|
||||
pci_find_host_bridge
|
||||
platform_get_irq_byname
|
||||
|
||||
# required by brcmstb_memc.ko
|
||||
of_match_device
|
||||
|
||||
@@ -908,9 +910,6 @@
|
||||
genphy_c37_read_status
|
||||
genphy_suspend
|
||||
|
||||
# required by btbcm.ko
|
||||
efi
|
||||
|
||||
# required by btsdio.ko
|
||||
sdio_claim_host
|
||||
sdio_claim_irq
|
||||
@@ -1082,7 +1081,6 @@
|
||||
phy_connect_direct
|
||||
phy_ethtool_ksettings_get
|
||||
phy_ethtool_ksettings_set
|
||||
phy_ethtool_set_wol
|
||||
phy_get_pause
|
||||
phy_init_hw
|
||||
phy_resume
|
||||
@@ -1420,10 +1418,12 @@
|
||||
bitmap_find_free_region
|
||||
bitmap_release_region
|
||||
devm_pci_alloc_host_bridge
|
||||
devm_phy_optional_get
|
||||
irq_chip_ack_parent
|
||||
irq_domain_get_irq_data
|
||||
irq_domain_set_info
|
||||
of_pci_get_max_link_speed
|
||||
of_property_read_variable_u16_array
|
||||
of_property_read_variable_u64_array
|
||||
pcie_link_speed
|
||||
pci_generic_config_read
|
||||
@@ -1447,6 +1447,12 @@
|
||||
# required by phy-brcm-sata.ko
|
||||
of_phy_simple_xlate
|
||||
|
||||
# required by phy-brcm-pcie.ko
|
||||
__copy_overflow
|
||||
debugfs_initialized
|
||||
regmap_read
|
||||
strsep
|
||||
|
||||
# required by phy-brcm-usb-dvr.ko
|
||||
brcmstb_get_family_id
|
||||
brcmstb_get_product_id
|
||||
|
||||
@@ -1720,6 +1720,11 @@
|
||||
net_selftest_get_count
|
||||
net_selftest_get_strings
|
||||
nf_conntrack_destroy
|
||||
nfnetlink_subsys_register
|
||||
nfnetlink_subsys_unregister
|
||||
nfnetlink_unicast
|
||||
nfnl_lock
|
||||
nfnl_unlock
|
||||
nf_register_net_hooks
|
||||
nf_unregister_net_hooks
|
||||
nla_find
|
||||
@@ -3569,6 +3574,8 @@
|
||||
xsk_tx_peek_desc
|
||||
xsk_tx_release
|
||||
xsk_uses_need_wakeup
|
||||
xt_register_matches
|
||||
xt_unregister_matches
|
||||
zlib_deflate
|
||||
zlib_deflateEnd
|
||||
zlib_deflateInit2
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
have_governor_per_policy
|
||||
i2c_smbus_read_word_data
|
||||
i2c_smbus_write_word_data
|
||||
__icmp_send
|
||||
iio_channel_get
|
||||
iio_channel_release
|
||||
iio_get_channel_type
|
||||
|
||||
@@ -106,10 +106,12 @@
|
||||
blk_mq_free_request
|
||||
blk_mq_free_tag_set
|
||||
blk_mq_map_queues
|
||||
blk_mq_quiesce_queue
|
||||
blk_mq_start_request
|
||||
blk_mq_start_stopped_hw_queues
|
||||
blk_mq_stop_hw_queues
|
||||
blk_mq_unique_tag
|
||||
blk_mq_unquiesce_queue
|
||||
blk_mq_update_nr_hw_queues
|
||||
blk_op_str
|
||||
blk_queue_chunk_sectors
|
||||
@@ -286,6 +288,7 @@
|
||||
__cpu_present_mask
|
||||
cpupri_find_fitness
|
||||
cpu_scale
|
||||
cpuset_cpus_allowed
|
||||
cpus_read_lock
|
||||
cpus_read_unlock
|
||||
cpu_subsys
|
||||
@@ -1359,6 +1362,8 @@
|
||||
log_threaded_irq_wakeup_reason
|
||||
log_write_mmio
|
||||
loops_per_jiffy
|
||||
lru_cache_disable
|
||||
lru_disable_count
|
||||
mac_pton
|
||||
mas_empty_area_rev
|
||||
mas_find
|
||||
@@ -1960,6 +1965,7 @@
|
||||
rtnl_trylock
|
||||
rtnl_unlock
|
||||
runqueues
|
||||
sbitmap_weight
|
||||
sched_clock
|
||||
sched_feat_keys
|
||||
sched_setattr_nocheck
|
||||
@@ -2299,6 +2305,7 @@
|
||||
tasklet_setup
|
||||
tasklet_unlock_wait
|
||||
__task_pid_nr_ns
|
||||
__task_rq_lock
|
||||
task_rq_lock
|
||||
tcpci_get_tcpm_port
|
||||
tcpci_irq
|
||||
@@ -2448,6 +2455,7 @@
|
||||
__traceiter_android_vh_usb_dev_resume
|
||||
__traceiter_android_vh_use_amu_fie
|
||||
__traceiter_android_vh_vmscan_kswapd_done
|
||||
__traceiter_android_vh_calculate_totalreserve_pages
|
||||
__traceiter_clock_set_rate
|
||||
__traceiter_cma_alloc_finish
|
||||
__traceiter_cma_alloc_start
|
||||
@@ -2588,6 +2596,7 @@
|
||||
__tracepoint_android_vh_usb_dev_resume
|
||||
__tracepoint_android_vh_use_amu_fie
|
||||
__tracepoint_android_vh_vmscan_kswapd_done
|
||||
__tracepoint_android_vh_calculate_totalreserve_pages
|
||||
__tracepoint_clock_set_rate
|
||||
__tracepoint_cma_alloc_finish
|
||||
__tracepoint_cma_alloc_start
|
||||
|
||||
@@ -2266,6 +2266,7 @@
|
||||
of_thermal_get_trip_points
|
||||
of_thermal_is_trip_valid
|
||||
of_translate_address
|
||||
of_update_property
|
||||
on_each_cpu_cond_mask
|
||||
oops_in_progress
|
||||
open_candev
|
||||
@@ -3538,6 +3539,7 @@
|
||||
__traceiter_android_vh_ufs_send_uic_command
|
||||
__traceiter_android_vh_ufs_update_sdev
|
||||
__traceiter_android_vh_update_topology_flags_workfn
|
||||
__traceiter_android_vh_vprintk_store
|
||||
__traceiter_binder_transaction_received
|
||||
__traceiter_cpu_frequency_limits
|
||||
__traceiter_cpu_idle
|
||||
@@ -3691,6 +3693,7 @@
|
||||
__tracepoint_android_vh_ufs_send_uic_command
|
||||
__tracepoint_android_vh_ufs_update_sdev
|
||||
__tracepoint_android_vh_update_topology_flags_workfn
|
||||
__tracepoint_android_vh_vprintk_store
|
||||
__tracepoint_binder_transaction_received
|
||||
__tracepoint_cpu_frequency_limits
|
||||
__tracepoint_cpu_idle
|
||||
@@ -4162,6 +4165,7 @@
|
||||
__xa_insert
|
||||
xa_load
|
||||
xa_store
|
||||
xas_load
|
||||
xdp_convert_zc_to_xdp_frame
|
||||
xdp_do_flush
|
||||
xdp_do_redirect
|
||||
|
||||
@@ -2498,6 +2498,7 @@
|
||||
__drm_atomic_state_free
|
||||
drm_bridge_chain_mode_set
|
||||
drm_bridge_get_edid
|
||||
drm_bridge_is_panel
|
||||
drm_connector_list_update
|
||||
drm_crtc_cleanup
|
||||
drm_crtc_enable_color_mgmt
|
||||
@@ -2521,6 +2522,7 @@
|
||||
drm_flip_work_init
|
||||
drm_flip_work_queue
|
||||
drm_format_info
|
||||
drm_format_info_bpp
|
||||
drm_format_info_min_pitch
|
||||
drm_framebuffer_cleanup
|
||||
drm_framebuffer_init
|
||||
@@ -2543,7 +2545,9 @@
|
||||
drm_kms_helper_poll_init
|
||||
drm_mm_init
|
||||
drm_mm_insert_node_in_range
|
||||
drmm_of_get_bridge
|
||||
drmm_mode_config_init
|
||||
drmm_panel_bridge_add
|
||||
drm_mm_print
|
||||
drm_mm_remove_node
|
||||
drm_mm_reserve_node
|
||||
@@ -2567,6 +2571,7 @@
|
||||
drm_mode_validate_ycbcr420
|
||||
drm_of_crtc_port_mask
|
||||
drm_of_encoder_active_endpoint
|
||||
drm_panel_bridge_set_orientation
|
||||
drm_plane_cleanup
|
||||
drm_plane_create_alpha_property
|
||||
drm_plane_create_blend_mode_property
|
||||
|
||||
@@ -472,6 +472,9 @@ __tracepoint_android_vh_page_should_be_protected
|
||||
__traceiter_android_vh_page_referenced_check_bypass
|
||||
__tracepoint_android_vh_page_referenced_check_bypass
|
||||
__page_mapcount
|
||||
folio_mapcount
|
||||
__traceiter_android_vh_folio_referenced_check_bypass
|
||||
__tracepoint_android_vh_folio_referenced_check_bypass
|
||||
|
||||
#required by mi_async_reclaim.ko
|
||||
__traceiter_android_vh_handle_trylock_failed_folio
|
||||
@@ -485,3 +488,12 @@ __tracepoint_android_vh_get_folio_trylock_result
|
||||
__traceiter_android_vh_do_folio_trylock
|
||||
__tracepoint_android_vh_do_folio_trylock
|
||||
reclaim_pages
|
||||
|
||||
#required by mi_iod_debug.ko
|
||||
page_swap_info
|
||||
|
||||
# required by launch_boost driver
|
||||
__traceiter_android_vh_filemap_read
|
||||
__tracepoint_android_vh_filemap_read
|
||||
__traceiter_android_vh_filemap_map_pages_range
|
||||
__tracepoint_android_vh_filemap_map_pages_range
|
||||
|
||||
29
android/abi_gki_aarch64_zebra
Normal file
29
android/abi_gki_aarch64_zebra
Normal file
@@ -0,0 +1,29 @@
|
||||
[abi_symbol_list]
|
||||
|
||||
#required by pegasus.ko
|
||||
mii_nway_restart
|
||||
mii_link_ok
|
||||
mii_ethtool_get_link_ksettings
|
||||
mii_ethtool_set_link_ksettings
|
||||
|
||||
#required by susc95xx.ko
|
||||
usbnet_get_endpoints
|
||||
usbnet_write_cmd
|
||||
usbnet_write_cmd_nopm
|
||||
usbnet_read_cmd
|
||||
usbnet_read_cmd_nopm
|
||||
usbnet_open
|
||||
usbnet_stop
|
||||
usbnet_start_xmit
|
||||
usbnet_change_mtu
|
||||
usbnet_tx_timeout
|
||||
usbnet_write_cmd_async
|
||||
usbnet_get_drvinfo
|
||||
usbnet_get_msglevel
|
||||
usbnet_set_msglevel
|
||||
usbnet_defer_kevent
|
||||
usbnet_skb_return
|
||||
usbnet_probe
|
||||
usbnet_disconnect
|
||||
usbnet_suspend
|
||||
usbnet_resume
|
||||
@@ -97,7 +97,12 @@ h4_recv_buf
|
||||
hci_alloc_dev_priv
|
||||
hci_cmd_sync
|
||||
hci_cmd_sync_cancel
|
||||
hci_cmd_sync_cancel_entry
|
||||
hci_cmd_sync_dequeue
|
||||
hci_cmd_sync_dequeue_once
|
||||
hci_cmd_sync_lookup_entry
|
||||
hci_cmd_sync_queue
|
||||
hci_cmd_sync_queue_once
|
||||
hci_cmd_sync_status
|
||||
hci_cmd_sync_submit
|
||||
hci_conn_check_secure
|
||||
@@ -346,4 +351,4 @@ wwan_port_txoff
|
||||
wwan_port_txon
|
||||
wwan_register_ops
|
||||
wwan_remove_port
|
||||
wwan_unregister_ops
|
||||
wwan_unregister_ops
|
||||
|
||||
@@ -129,6 +129,7 @@ CONFIG_CMA_DEBUGFS=y
|
||||
CONFIG_CMA_AREAS=32
|
||||
# CONFIG_ZONE_DMA is not set
|
||||
CONFIG_ZONE_DEVICE=y
|
||||
CONFIG_MEMFD_ASHMEM_SHIM=y
|
||||
CONFIG_ANON_VMA_NAME=y
|
||||
CONFIG_USERFAULTFD=y
|
||||
CONFIG_LRU_GEN=y
|
||||
|
||||
@@ -119,6 +119,7 @@ CONFIG_CMA_DEBUGFS=y
|
||||
CONFIG_CMA_AREAS=16
|
||||
# CONFIG_ZONE_DMA is not set
|
||||
CONFIG_ZONE_DEVICE=y
|
||||
CONFIG_MEMFD_ASHMEM_SHIM=y
|
||||
CONFIG_ANON_VMA_NAME=y
|
||||
CONFIG_USERFAULTFD=y
|
||||
CONFIG_LRU_GEN=y
|
||||
|
||||
@@ -472,3 +472,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmc_attach_sd);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sdhci_get_cd);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmc_gpio_cd_irqt);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_trigger_vendor_lmk_kill);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_filemap_map_pages_range);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_vprintk_store);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_folio_referenced_check_bypass);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_calculate_totalreserve_pages);
|
||||
|
||||
@@ -1884,6 +1884,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_update_property);
|
||||
|
||||
static void of_alias_add(struct alias_prop *ap, struct device_node *np,
|
||||
int id, const char *stem, int stem_len)
|
||||
|
||||
@@ -104,6 +104,20 @@ static struct kmem_cache *ashmem_range_cachep __read_mostly;
|
||||
*/
|
||||
static struct lock_class_key backing_shmem_inode_class;
|
||||
|
||||
/* Enable unpinning feature by default to retain compatibility with existing behavior. */
|
||||
static bool unpinning_enable = true;
|
||||
|
||||
/*
|
||||
* memfd does not allow removing permissions to map a buffer with PROT_READ or PROT_EXEC. These
|
||||
* variables are exposed as tunables so that they can be used to make ashmem behave more like memfd
|
||||
* for test purposes.
|
||||
*
|
||||
* They are set to false by default to retain compatibility with the original behavior of the
|
||||
* driver.
|
||||
*/
|
||||
static bool ignore_unset_prot_read;
|
||||
static bool ignore_unset_prot_exec;
|
||||
|
||||
static inline unsigned long range_size(struct ashmem_range *range)
|
||||
{
|
||||
return range->pgend - range->pgstart + 1;
|
||||
@@ -479,6 +493,9 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||
{
|
||||
unsigned long freed = 0;
|
||||
|
||||
if (!unpinning_enable)
|
||||
return 0;
|
||||
|
||||
/* We might recurse into filesystem code, so bail out if necessary */
|
||||
if (!(sc->gfp_mask & __GFP_FS))
|
||||
return SHRINK_STOP;
|
||||
@@ -524,7 +541,7 @@ ashmem_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
||||
* objects on the list. This means the scan function needs to return the
|
||||
* number of pages freed, not the number of objects scanned.
|
||||
*/
|
||||
return lru_count;
|
||||
return unpinning_enable ? lru_count : SHRINK_EMPTY;
|
||||
}
|
||||
|
||||
static struct shrinker ashmem_shrinker = {
|
||||
@@ -543,6 +560,14 @@ static int set_prot_mask(struct ashmem_area *asma, unsigned long prot)
|
||||
|
||||
mutex_lock(&ashmem_mutex);
|
||||
|
||||
/* Ensure the buffer can only be mapped with PROT_READ iff it has that permission. */
|
||||
if (ignore_unset_prot_read)
|
||||
prot |= asma->prot_mask & PROT_READ;
|
||||
|
||||
/* Ensure the buffer can only be mapped with PROT_EXEC iff it has that permission. */
|
||||
if (ignore_unset_prot_exec)
|
||||
prot |= asma->prot_mask & PROT_EXEC;
|
||||
|
||||
/* the user can only remove, not add, protection bits */
|
||||
if ((asma->prot_mask & prot) != prot) {
|
||||
ret = -EINVAL;
|
||||
@@ -802,7 +827,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
|
||||
ret = ashmem_pin(asma, pgstart, pgend, &range);
|
||||
break;
|
||||
case ASHMEM_UNPIN:
|
||||
ret = ashmem_unpin(asma, pgstart, pgend, &range);
|
||||
ret = unpinning_enable ? ashmem_unpin(asma, pgstart, pgend, &range) : 0;
|
||||
break;
|
||||
case ASHMEM_GET_PIN_STATUS:
|
||||
ret = ashmem_get_pin_status(asma, pgstart, pgend);
|
||||
@@ -921,6 +946,52 @@ static void ashmem_show_fdinfo(struct seq_file *m, struct file *file)
|
||||
mutex_unlock(&ashmem_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int unpinning_enable_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = &unpinning_enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ignore_unset_prot_read_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = &ignore_unset_prot_read;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ignore_unset_prot_exec_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = &ignore_unset_prot_exec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t attr_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
bool *attrp = file->private_data;
|
||||
char val_str[2];
|
||||
|
||||
val_str[0] = *attrp ? '1' : '0';
|
||||
val_str[1] = '\n';
|
||||
return simple_read_from_buffer(buf, count, ppos, val_str, sizeof(val_str));
|
||||
}
|
||||
|
||||
static ssize_t attr_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
bool *attrp = file->private_data;
|
||||
bool enable;
|
||||
ssize_t ret = count;
|
||||
|
||||
if (!kstrtobool_from_user(buf, count, &enable)) {
|
||||
mutex_lock(&ashmem_mutex);
|
||||
*attrp = enable;
|
||||
mutex_unlock(&ashmem_mutex);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations ashmem_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ashmem_open,
|
||||
@@ -946,15 +1017,54 @@ int is_ashmem_file(struct file *file)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(is_ashmem_file);
|
||||
|
||||
static struct miscdevice ashmem_misc = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "ashmem",
|
||||
.fops = &ashmem_fops,
|
||||
static const struct file_operations unpinning_enable_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = unpinning_enable_open,
|
||||
.read = attr_read,
|
||||
.write = attr_write,
|
||||
};
|
||||
|
||||
static const struct file_operations ignore_unset_prot_read_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ignore_unset_prot_read_open,
|
||||
.read = attr_read,
|
||||
.write = attr_write,
|
||||
};
|
||||
|
||||
static const struct file_operations ignore_unset_prot_exec_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ignore_unset_prot_exec_open,
|
||||
.read= attr_read,
|
||||
.write = attr_write,
|
||||
};
|
||||
|
||||
static struct miscdevice ashmem_miscs[] = {
|
||||
{
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "ashmem",
|
||||
.fops = &ashmem_fops,
|
||||
},
|
||||
{
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "ashmem_unpinning_enable",
|
||||
.fops = &unpinning_enable_fops,
|
||||
},
|
||||
{
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "ashmem_ignore_unset_prot_read",
|
||||
.fops = &ignore_unset_prot_read_fops,
|
||||
},
|
||||
{
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "ashmem_ignore_unset_prot_exec",
|
||||
.fops = &ignore_unset_prot_exec_fops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ashmem_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
int i;
|
||||
|
||||
ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",
|
||||
sizeof(struct ashmem_area),
|
||||
@@ -972,10 +1082,12 @@ static int __init ashmem_init(void)
|
||||
goto out_free1;
|
||||
}
|
||||
|
||||
ret = misc_register(&ashmem_misc);
|
||||
if (ret) {
|
||||
pr_err("failed to register misc device!\n");
|
||||
goto out_free2;
|
||||
for (i = 0; i < ARRAY_SIZE(ashmem_miscs); i++) {
|
||||
ret = misc_register(&ashmem_miscs[i]);
|
||||
if (ret) {
|
||||
pr_err("failed to register %s misc device!\n", ashmem_miscs[i].name);
|
||||
goto out_demisc;
|
||||
}
|
||||
}
|
||||
|
||||
ret = register_shrinker(&ashmem_shrinker, "android-ashmem");
|
||||
@@ -989,8 +1101,8 @@ static int __init ashmem_init(void)
|
||||
return 0;
|
||||
|
||||
out_demisc:
|
||||
misc_deregister(&ashmem_misc);
|
||||
out_free2:
|
||||
while (--i >= 0)
|
||||
misc_deregister(&ashmem_miscs[i]);
|
||||
kmem_cache_destroy(ashmem_range_cachep);
|
||||
out_free1:
|
||||
kmem_cache_destroy(ashmem_area_cachep);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "iostat.h"
|
||||
#include <trace/events/f2fs.h>
|
||||
|
||||
#define DEFAULT_CHECKPOINT_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
|
||||
#define DEFAULT_CHECKPOINT_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 3))
|
||||
|
||||
static struct kmem_cache *ino_entry_slab;
|
||||
struct kmem_cache *f2fs_inode_entry_slab;
|
||||
|
||||
@@ -1815,16 +1815,30 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
|
||||
|
||||
map.m_len = sec_blks;
|
||||
next_alloc:
|
||||
f2fs_down_write(&sbi->pin_sem);
|
||||
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
|
||||
if (has_not_enough_free_secs(sbi, 0, 0)) {
|
||||
f2fs_up_write(&sbi->pin_sem);
|
||||
err = -ENOSPC;
|
||||
f2fs_warn(sbi,
|
||||
"ino:%lu, start:%lu, end:%lu, need to trigger GC to "
|
||||
"reclaim enough free segment when checkpoint is enabled",
|
||||
inode->i_ino, pg_start, pg_end);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_not_enough_free_secs(sbi, 0,
|
||||
GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
|
||||
f2fs_down_write(&sbi->gc_lock);
|
||||
err = f2fs_gc(sbi, &gc_control);
|
||||
if (err && err != -ENODATA)
|
||||
if (err && err != -ENODATA) {
|
||||
f2fs_up_write(&sbi->pin_sem);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
f2fs_down_write(&sbi->pin_sem);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
|
||||
f2fs_unlock_op(sbi);
|
||||
@@ -3751,7 +3765,7 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count,
|
||||
to_reserved = cluster_size - compr_blocks - reserved;
|
||||
|
||||
/* for the case all blocks in cluster were reserved */
|
||||
if (to_reserved == 1) {
|
||||
if (reserved && to_reserved == 1) {
|
||||
dn->ofs_in_node += cluster_size;
|
||||
goto next;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,8 @@ void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync)
|
||||
if (f2fs_inode_dirtied(inode, sync))
|
||||
return;
|
||||
|
||||
if (f2fs_is_atomic_file(inode)) {
|
||||
set_inode_flag(inode, FI_ATOMIC_DIRTIED);
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
return;
|
||||
}
|
||||
|
||||
mark_inode_dirty_sync(inode);
|
||||
}
|
||||
|
||||
@@ -201,6 +201,12 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
if (is_inode_flag_set(inode, FI_ATOMIC_DIRTIED)) {
|
||||
clear_inode_flag(inode, FI_ATOMIC_DIRTIED);
|
||||
/*
|
||||
* The vfs inode keeps clean during commit, but the f2fs inode
|
||||
* doesn't. So clear the dirty state after commit and let
|
||||
* f2fs_mark_inode_dirty_sync ensure a consistent dirty state.
|
||||
*/
|
||||
f2fs_inode_synced(inode);
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
stat_dec_atomic_inode(inode);
|
||||
|
||||
@@ -1533,6 +1533,10 @@ int f2fs_inode_dirtied(struct inode *inode, bool sync)
|
||||
inc_page_count(sbi, F2FS_DIRTY_IMETA);
|
||||
}
|
||||
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||
|
||||
if (!ret && f2fs_is_atomic_file(inode))
|
||||
set_inode_flag(inode, FI_ATOMIC_DIRTIED);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1942,7 +1942,8 @@ static int userfaultfd_move(struct userfaultfd_ctx *ctx,
|
||||
return ret;
|
||||
|
||||
if (uffdio_move.mode & ~(UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES|
|
||||
UFFDIO_MOVE_MODE_DONTWAKE))
|
||||
UFFDIO_MOVE_MODE_DONTWAKE|
|
||||
UFFDIO_MOVE_MODE_CONFIRM_FIXED))
|
||||
return -EINVAL;
|
||||
|
||||
if (mmget_not_zero(mm)) {
|
||||
|
||||
@@ -342,6 +342,84 @@ TRACE_EVENT(mm_alloc_contig_migrate_range_info,
|
||||
__entry->nr_mapped)
|
||||
);
|
||||
|
||||
TRACE_EVENT(mm_setup_per_zone_wmarks,
|
||||
|
||||
TP_PROTO(struct zone *zone),
|
||||
|
||||
TP_ARGS(zone),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, node_id)
|
||||
__string(name, zone->name)
|
||||
__field(unsigned long, watermark_min)
|
||||
__field(unsigned long, watermark_low)
|
||||
__field(unsigned long, watermark_high)
|
||||
__field(unsigned long, watermark_promo)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->node_id = zone->zone_pgdat->node_id;
|
||||
__assign_str(name, zone->name);
|
||||
__entry->watermark_min = zone->_watermark[WMARK_MIN];
|
||||
__entry->watermark_low = zone->_watermark[WMARK_LOW];
|
||||
__entry->watermark_high = zone->_watermark[WMARK_HIGH];
|
||||
__entry->watermark_promo = zone->_watermark[WMARK_PROMO];
|
||||
),
|
||||
|
||||
TP_printk("node_id=%d zone name=%s watermark min=%lu low=%lu high=%lu promo=%lu",
|
||||
__entry->node_id,
|
||||
__get_str(name),
|
||||
__entry->watermark_min,
|
||||
__entry->watermark_low,
|
||||
__entry->watermark_high,
|
||||
__entry->watermark_promo)
|
||||
);
|
||||
|
||||
TRACE_EVENT(mm_setup_per_zone_lowmem_reserve,
|
||||
|
||||
TP_PROTO(struct zone *zone, struct zone *upper_zone, long lowmem_reserve),
|
||||
|
||||
TP_ARGS(zone, upper_zone, lowmem_reserve),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, node_id)
|
||||
__string(name, zone->name)
|
||||
__string(upper_name, upper_zone->name)
|
||||
__field(long, lowmem_reserve)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->node_id = zone->zone_pgdat->node_id;
|
||||
__assign_str(name, zone->name);
|
||||
__assign_str(upper_name, zone->name);
|
||||
__entry->lowmem_reserve = lowmem_reserve;
|
||||
),
|
||||
|
||||
TP_printk("node_id=%d zone name=%s upper_zone name=%s lowmem_reserve_pages=%ld",
|
||||
__entry->node_id,
|
||||
__get_str(name),
|
||||
__get_str(upper_name),
|
||||
__entry->lowmem_reserve)
|
||||
);
|
||||
|
||||
TRACE_EVENT(mm_calculate_totalreserve_pages,
|
||||
|
||||
TP_PROTO(unsigned long totalreserve_pages),
|
||||
|
||||
TP_ARGS(totalreserve_pages),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned long, totalreserve_pages)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->totalreserve_pages = totalreserve_pages;
|
||||
),
|
||||
|
||||
TP_printk("totalreserve_pages=%lu", __entry->totalreserve_pages)
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Required for uniquely and securely identifying mm in rss_stat tracepoint.
|
||||
*/
|
||||
|
||||
@@ -298,6 +298,13 @@ DECLARE_HOOK(android_vh_alloc_flags_cma_adjust,
|
||||
DECLARE_HOOK(android_vh_rmqueue_cma_fallback,
|
||||
TP_PROTO(struct zone *zone, unsigned int order, struct page **page),
|
||||
TP_ARGS(zone, order, page));
|
||||
DECLARE_HOOK(android_vh_filemap_map_pages_range,
|
||||
TP_PROTO(struct file *file, pgoff_t orig_start_pgoff,
|
||||
pgoff_t last_pgoff, vm_fault_t ret),
|
||||
TP_ARGS(file, orig_start_pgoff, last_pgoff, ret));
|
||||
DECLARE_HOOK(android_vh_calculate_totalreserve_pages,
|
||||
TP_PROTO(bool *skip),
|
||||
TP_ARGS(skip));
|
||||
#endif /* _TRACE_HOOK_MM_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
||||
@@ -13,6 +13,10 @@ DECLARE_HOOK(android_vh_printk_hotplug,
|
||||
TP_PROTO(int *flag),
|
||||
TP_ARGS(flag));
|
||||
|
||||
DECLARE_HOOK(android_vh_vprintk_store,
|
||||
TP_PROTO(u64 time, char *m, size_t len),
|
||||
TP_ARGS(time, m, len));
|
||||
|
||||
#endif /* _TRACE_HOOK_PRINTK_H */
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
||||
|
||||
@@ -79,6 +79,9 @@ DECLARE_HOOK(android_vh_do_folio_trylock,
|
||||
DECLARE_HOOK(android_vh_page_referenced_check_bypass,
|
||||
TP_PROTO(struct folio *folio, unsigned long nr_to_scan, int lru, bool *bypass),
|
||||
TP_ARGS(folio, nr_to_scan, lru, bypass));
|
||||
DECLARE_HOOK(android_vh_folio_referenced_check_bypass,
|
||||
TP_PROTO(struct folio *folio, s8 priority, unsigned long nr_to_scan, int lru, bool *bypass),
|
||||
TP_ARGS(folio, priority, nr_to_scan, lru, bypass));
|
||||
DECLARE_HOOK(android_vh_should_memcg_bypass,
|
||||
TP_PROTO(struct mem_cgroup *memcg, int priority, bool *bypass),
|
||||
TP_ARGS(memcg, priority, bypass));
|
||||
|
||||
@@ -325,6 +325,13 @@ struct uffdio_move {
|
||||
*/
|
||||
#define UFFDIO_MOVE_MODE_DONTWAKE ((__u64)1<<0)
|
||||
#define UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES ((__u64)1<<1)
|
||||
/*
|
||||
* To confirm if the ioctl has fixes to avoid panic when src folio is
|
||||
* in swap-cache. Also, to avoid livelock when multiple threads try
|
||||
* to move same src folio. It's a KMI workaround and cannot be relied
|
||||
* upon by userspace.
|
||||
*/
|
||||
#define UFFDIO_MOVE_MODE_CONFIRM_FIXED ((__u64)1<<63)
|
||||
__u64 mode;
|
||||
/*
|
||||
* "move" is written by the ioctl and must be at the end: the
|
||||
|
||||
@@ -2248,6 +2248,7 @@ int vprintk_store(int facility, int level,
|
||||
r.info->flags = flags & 0x1f;
|
||||
r.info->ts_nsec = ts_nsec;
|
||||
r.info->caller_id = caller_id;
|
||||
trace_android_vh_vprintk_store(r.info->ts_nsec, r.text_buf, r.info->text_len);
|
||||
if (dev_info)
|
||||
memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
|
||||
|
||||
|
||||
11
mm/Kconfig
11
mm/Kconfig
@@ -1131,6 +1131,17 @@ config IO_MAPPING
|
||||
config ARCH_HAS_IOREMAP_PHYS_HOOKS
|
||||
bool
|
||||
|
||||
config MEMFD_ASHMEM_SHIM
|
||||
bool "Memfd ashmem ioctl compatibility support"
|
||||
depends on MEMFD_CREATE
|
||||
help
|
||||
This provides compatibility support for ashmem ioctl commands against
|
||||
memfd file descriptors. This is useful for compatibility on Android
|
||||
for older applications that may use ashmem's ioctl commands on the
|
||||
now memfds passed to them.
|
||||
|
||||
Unless you are running Android, say N.
|
||||
|
||||
config SECRETMEM
|
||||
def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@ obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o
|
||||
obj-$(CONFIG_ZONE_DEVICE) += memremap.o
|
||||
obj-$(CONFIG_HMM_MIRROR) += hmm.o
|
||||
obj-$(CONFIG_MEMFD_CREATE) += memfd.o
|
||||
obj-$(CONFIG_MEMFD_ASHMEM_SHIM) += memfd-ashmem-shim.o
|
||||
obj-$(CONFIG_MAPPING_DIRTY_HELPERS) += mapping_dirty_helpers.o
|
||||
obj-$(CONFIG_PTDUMP_CORE) += ptdump.o
|
||||
obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o
|
||||
|
||||
@@ -3468,12 +3468,14 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,
|
||||
unsigned int mmap_miss = READ_ONCE(file->f_ra.mmap_miss);
|
||||
vm_fault_t ret = 0;
|
||||
pgoff_t first_pgoff = 0;
|
||||
pgoff_t orig_start_pgoff = start_pgoff;
|
||||
|
||||
rcu_read_lock();
|
||||
folio = first_map_page(mapping, &xas, end_pgoff);
|
||||
if (!folio)
|
||||
goto out;
|
||||
first_pgoff = xas.xa_index;
|
||||
orig_start_pgoff = xas.xa_index;
|
||||
|
||||
if (filemap_map_pmd(vmf, &folio->page)) {
|
||||
ret = VM_FAULT_NOPAGE;
|
||||
@@ -3530,6 +3532,7 @@ out:
|
||||
rcu_read_unlock();
|
||||
WRITE_ONCE(file->f_ra.mmap_miss, mmap_miss);
|
||||
trace_android_vh_filemap_map_pages(file, first_pgoff, last_pgoff, ret);
|
||||
trace_android_vh_filemap_map_pages_range(file, orig_start_pgoff, last_pgoff, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
52
mm/memfd-ashmem-shim-internal.h
Normal file
52
mm/memfd-ashmem-shim-internal.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Ashmem compatability for memfd
|
||||
*
|
||||
* Copyright (c) 2025, Google LLC.
|
||||
* Author: Isaac J. Manjarres <isaacmanjarres@google.com>
|
||||
*/
|
||||
|
||||
#ifndef _MM_MEMFD_ASHMEM_SHIM_INTERNAL_H
|
||||
#define _MM_MEMFD_ASHMEM_SHIM_INTERNAL_H
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define ASHMEM_NAME_LEN 256
|
||||
|
||||
/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
|
||||
#define ASHMEM_NOT_PURGED 0
|
||||
#define ASHMEM_WAS_PURGED 1
|
||||
|
||||
/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */
|
||||
#define ASHMEM_IS_UNPINNED 0
|
||||
#define ASHMEM_IS_PINNED 1
|
||||
|
||||
struct ashmem_pin {
|
||||
__u32 offset; /* offset into region, in bytes, page-aligned */
|
||||
__u32 len; /* length forward from offset, in bytes, page-aligned */
|
||||
};
|
||||
|
||||
#define __ASHMEMIOC 0x77
|
||||
|
||||
#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
|
||||
#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
|
||||
#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
|
||||
#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
|
||||
#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
|
||||
#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
|
||||
#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
|
||||
#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin)
|
||||
#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
|
||||
#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
|
||||
#define ASHMEM_GET_FILE_ID _IOR(__ASHMEMIOC, 11, unsigned long)
|
||||
|
||||
/* support of 32bit userspace on 64bit platforms */
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define COMPAT_ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, compat_size_t)
|
||||
#define COMPAT_ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned int)
|
||||
#endif
|
||||
|
||||
#endif /* _MM_MEMFD_ASHMEM_SHIM_INTERNAL_H */
|
||||
240
mm/memfd-ashmem-shim.c
Normal file
240
mm/memfd-ashmem-shim.c
Normal file
@@ -0,0 +1,240 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Ashmem compatability for memfd
|
||||
*
|
||||
* Copyright (c) 2025, Google LLC.
|
||||
* Author: Isaac J. Manjarres <isaacmanjarres@google.com>
|
||||
*/
|
||||
|
||||
#include <asm-generic/mman-common.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/memfd.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "memfd-ashmem-shim.h"
|
||||
#include "memfd-ashmem-shim-internal.h"
|
||||
|
||||
/* file_path() returns the path of the file including the root, hence the additional "/". */
|
||||
#define MEMFD_PATH_PREFIX "/memfd:"
|
||||
#define MEMFD_PATH_PREFIX_LEN (sizeof(MEMFD_PATH_PREFIX) - 1)
|
||||
|
||||
/* All memfd files are unlinked, and are therefore suffixed with the " (deleted)" string. */
|
||||
#define UNLINKED_FILE_SUFFIX " (deleted)"
|
||||
#define UNLINKED_FILE_SUFFIX_LEN (sizeof(UNLINKED_FILE_SUFFIX) - 1)
|
||||
|
||||
/*
|
||||
* 1 character for the start of the path (/), NAME_MAX for the maximum length of a full memfd file
|
||||
* name, UNLINKED_FILE_SUFFIX_LEN for the " (deleted)" suffix, and 1 for the NUL terminating
|
||||
* character.
|
||||
*/
|
||||
#define MAX_FILE_PATH_SIZE (1 + NAME_MAX + UNLINKED_FILE_SUFFIX_LEN + 1)
|
||||
|
||||
static char *get_memfd_file_name(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
char *name_end;
|
||||
char *path = file_path(file, buf, size);
|
||||
|
||||
if (IS_ERR(path))
|
||||
return path;
|
||||
|
||||
/* Only handle memfds; we cannot make assumptions about other file names. */
|
||||
name_end = strstr(path, UNLINKED_FILE_SUFFIX);
|
||||
if ((strstr(path, MEMFD_PATH_PREFIX) != path) || !name_end)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/*
|
||||
* Since file_path() returns the full path of the file, including the root, the format will
|
||||
* be:
|
||||
*
|
||||
* "/memfd:testbuf (deleted)"
|
||||
*
|
||||
* But the ASHMEM_GET_NAME ioctl only returns the name of the buffer without any prefixes
|
||||
* or suffixes. So, terminate the string at the start of the " (deleted)" suffix so that
|
||||
* strlen() can be used on it from the start of the name.
|
||||
*/
|
||||
*name_end = '\0';
|
||||
|
||||
/* return a pointer to the start of the name */
|
||||
return &path[MEMFD_PATH_PREFIX_LEN];
|
||||
}
|
||||
|
||||
static long get_name(struct file *file, void __user *name)
|
||||
{
|
||||
char buf[MAX_FILE_PATH_SIZE];
|
||||
char *file_name = get_memfd_file_name(file, buf, sizeof(buf));
|
||||
size_t len;
|
||||
|
||||
if (IS_ERR(file_name))
|
||||
return PTR_ERR(file_name);
|
||||
|
||||
/*
|
||||
* The expectation is that the user provided buffer is ASHMEM_NAME_LEN in size, which is
|
||||
* larger than the maximum size of a name for a memfd buffer, so the name should always fit
|
||||
* within the given buffer.
|
||||
*
|
||||
* However, we should ensure that the string will indeed fit in the user provided buffer.
|
||||
*
|
||||
* Add 1 to the copy size to account for the NUL terminator
|
||||
*/
|
||||
len = strlen(file_name) + 1;
|
||||
if (len > ASHMEM_NAME_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
return copy_to_user(name, file_name, len) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static long get_prot_mask(struct file *file)
|
||||
{
|
||||
long prot_mask = PROT_READ | PROT_EXEC;
|
||||
long seals = memfd_fcntl(file, F_GET_SEALS, 0);
|
||||
|
||||
if (seals < 0)
|
||||
return seals;
|
||||
|
||||
/* memfds are readable and executable by default. Only writability can be changed. */
|
||||
if (!(seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE)))
|
||||
prot_mask |= PROT_WRITE;
|
||||
|
||||
return prot_mask;
|
||||
}
|
||||
|
||||
static long set_prot_mask(struct file *file, unsigned long prot)
|
||||
{
|
||||
long curr_prot = get_prot_mask(file);
|
||||
long ret = 0;
|
||||
|
||||
if (curr_prot < 0)
|
||||
return curr_prot;
|
||||
|
||||
/*
|
||||
* memfds are always readable and executable; there is no way to remove either mapping
|
||||
* permission, nor is there a known usecase that requires it.
|
||||
*
|
||||
* Attempting to remove either of these mapping permissions will return successfully, but
|
||||
* will be a nop, as the buffer will still be mappable with these permissions.
|
||||
*/
|
||||
prot |= PROT_READ | PROT_EXEC;
|
||||
|
||||
/* Only allow permissions to be removed. */
|
||||
if ((curr_prot & prot) != prot)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Removing PROT_WRITE:
|
||||
*
|
||||
* We could prevent any other mappings from having write permissions by adding the
|
||||
* F_SEAL_WRITE mapping. However, that would conflict with known usecases where it is
|
||||
* desirable to maintain an existing writable mapping, but forbid future writable mappings.
|
||||
*
|
||||
* To support those usecases, we use F_SEAL_FUTURE_WRITE.
|
||||
*/
|
||||
if (!(prot & PROT_WRITE))
|
||||
ret = memfd_fcntl(file, F_ADD_SEALS, F_SEAL_FUTURE_WRITE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* memfd_ashmem_shim_ioctl - ioctl handler for ashmem commands
|
||||
* @file: The shmem file.
|
||||
* @cmd: The ioctl command.
|
||||
* @arg: The argument for the ioctl command.
|
||||
*
|
||||
* The purpose of this handler is to allow old applications to continue working
|
||||
* on newer kernels by allowing them to invoke ashmem ioctl commands on memfds.
|
||||
*
|
||||
* The ioctl handler attempts to retain as much compatibility with the ashmem
|
||||
* driver as possible.
|
||||
*/
|
||||
long memfd_ashmem_shim_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
long ret = -ENOTTY;
|
||||
unsigned long inode_nr;
|
||||
|
||||
switch (cmd) {
|
||||
/*
|
||||
* Older applications won't create memfds and try to use ASHMEM_SET_NAME/ASHMEM_SET_SIZE on
|
||||
* them intentionally.
|
||||
*
|
||||
* Instead, we can end up in this scenario if an old application receives a memfd that was
|
||||
* created by another process.
|
||||
*
|
||||
* However, the current process shouldn't expect to be able to reliably [re]name/size a
|
||||
* buffer that was shared with it, since the process that shared that buffer with it, or
|
||||
* any other process that references the buffer could have already mapped it.
|
||||
*
|
||||
* Additionally in the case of ASHMEM_SET_SIZE, when processes create memfds that are going
|
||||
* to be shared with other processes in Android, they also specify the size of the memory
|
||||
* region and seal the file against any size changes. Therefore, ASHMEM_SET_SIZE should not
|
||||
* be supported anyway.
|
||||
*
|
||||
* Therefore, it is reasonable to return -EINVAL here, as if the buffer was already mapped.
|
||||
*/
|
||||
case ASHMEM_SET_NAME:
|
||||
case ASHMEM_SET_SIZE:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case ASHMEM_GET_NAME:
|
||||
ret = get_name(file, (void __user *)arg);
|
||||
break;
|
||||
case ASHMEM_GET_SIZE:
|
||||
ret = i_size_read(file_inode(file));
|
||||
break;
|
||||
case ASHMEM_SET_PROT_MASK:
|
||||
ret = set_prot_mask(file, arg);
|
||||
break;
|
||||
case ASHMEM_GET_PROT_MASK:
|
||||
ret = get_prot_mask(file);
|
||||
break;
|
||||
/*
|
||||
* Unpinning ashmem buffers was deprecated with the release of Android 10,
|
||||
* as it did not yield any remarkable benefits. Therefore, ignore pinning
|
||||
* related requests.
|
||||
*
|
||||
* This makes it so that memory is always "pinned" or never entirely freed
|
||||
* until all references to the ashmem buffer are dropped. The memory occupied
|
||||
* by the buffer is still subject to being reclaimed (swapped out) under memory
|
||||
* pressure, but that is not the same as being freed.
|
||||
*
|
||||
* This makes it so that:
|
||||
*
|
||||
* 1. Memory is always pinned and therefore never purged.
|
||||
* 2. Requests to unpin memory (make it a candidate for being freed) are ignored.
|
||||
*/
|
||||
case ASHMEM_PIN:
|
||||
ret = ASHMEM_NOT_PURGED;
|
||||
break;
|
||||
case ASHMEM_UNPIN:
|
||||
ret = 0;
|
||||
break;
|
||||
case ASHMEM_GET_PIN_STATUS:
|
||||
ret = ASHMEM_IS_PINNED;
|
||||
break;
|
||||
case ASHMEM_PURGE_ALL_CACHES:
|
||||
ret = capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
|
||||
break;
|
||||
case ASHMEM_GET_FILE_ID:
|
||||
inode_nr = file_inode(file)->i_ino;
|
||||
if (copy_to_user((void __user *)arg, &inode_nr, sizeof(inode_nr)))
|
||||
ret = -EFAULT;
|
||||
else
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
long memfd_ashmem_shim_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (cmd == COMPAT_ASHMEM_SET_SIZE)
|
||||
cmd = ASHMEM_SET_SIZE;
|
||||
else if (cmd == COMPAT_ASHMEM_SET_PROT_MASK)
|
||||
cmd = ASHMEM_SET_PROT_MASK;
|
||||
|
||||
return memfd_ashmem_shim_ioctl(file, cmd, arg);
|
||||
}
|
||||
#endif
|
||||
21
mm/memfd-ashmem-shim.h
Normal file
21
mm/memfd-ashmem-shim.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __MM_MEMFD_ASHMEM_SHIM_H
|
||||
#define __MM_MEMFD_ASHMEM_SHIM_H
|
||||
|
||||
/*
|
||||
* mm/memfd-ashmem-shim.h
|
||||
*
|
||||
* Ashmem compatability for memfd
|
||||
*
|
||||
* Copyright (c) 2025, Google LLC.
|
||||
* Author: Isaac J. Manjarres <isaacmanjarres@google.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
long memfd_ashmem_shim_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
#ifdef CONFIG_COMPAT
|
||||
long memfd_ashmem_shim_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
#endif
|
||||
#endif /* __MM_MEMFD_ASHMEM_SHIM_H */
|
||||
@@ -8950,6 +8950,7 @@ static void calculate_totalreserve_pages(void)
|
||||
struct pglist_data *pgdat;
|
||||
unsigned long reserve_pages = 0;
|
||||
enum zone_type i, j;
|
||||
bool skip = false;
|
||||
|
||||
for_each_online_pgdat(pgdat) {
|
||||
|
||||
@@ -8978,6 +8979,10 @@ static void calculate_totalreserve_pages(void)
|
||||
}
|
||||
}
|
||||
totalreserve_pages = reserve_pages;
|
||||
trace_android_vh_calculate_totalreserve_pages(&skip);
|
||||
if (skip)
|
||||
return;
|
||||
trace_mm_calculate_totalreserve_pages(totalreserve_pages);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9007,6 +9012,8 @@ static void setup_per_zone_lowmem_reserve(void)
|
||||
zone->lowmem_reserve[j] = 0;
|
||||
else
|
||||
zone->lowmem_reserve[j] = managed_pages / ratio;
|
||||
trace_mm_setup_per_zone_lowmem_reserve(zone, upper_zone,
|
||||
zone->lowmem_reserve[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9070,6 +9077,7 @@ static void __setup_per_zone_wmarks(void)
|
||||
zone->_watermark[WMARK_LOW] = min_wmark_pages(zone) + tmp;
|
||||
zone->_watermark[WMARK_HIGH] = low_wmark_pages(zone) + tmp;
|
||||
zone->_watermark[WMARK_PROMO] = high_wmark_pages(zone) + tmp;
|
||||
trace_mm_setup_per_zone_wmarks(zone);
|
||||
|
||||
spin_unlock_irqrestore(&zone->lock, flags);
|
||||
}
|
||||
|
||||
10
mm/shmem.c
10
mm/shmem.c
@@ -89,6 +89,10 @@ static struct vfsmount *shm_mnt;
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#ifdef CONFIG_MEMFD_ASHMEM_SHIM
|
||||
#include "memfd-ashmem-shim.h"
|
||||
#endif
|
||||
|
||||
#define BLOCKS_PER_PAGE (PAGE_SIZE/512)
|
||||
#define VM_ACCT(size) (PAGE_ALIGN(size) >> PAGE_SHIFT)
|
||||
|
||||
@@ -3976,6 +3980,12 @@ static const struct file_operations shmem_file_operations = {
|
||||
.splice_write = iter_file_splice_write,
|
||||
.fallocate = shmem_fallocate,
|
||||
#endif
|
||||
#ifdef CONFIG_MEMFD_ASHMEM_SHIM
|
||||
.unlocked_ioctl = memfd_ashmem_shim_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = memfd_ashmem_shim_compat_ioctl,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct inode_operations shmem_inode_operations = {
|
||||
|
||||
@@ -3431,6 +3431,7 @@ struct swap_info_struct *page_swap_info(struct page *page)
|
||||
swp_entry_t entry = { .val = page_private(page) };
|
||||
return swp_swap_info(entry);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(page_swap_info);
|
||||
|
||||
/*
|
||||
* out-of-line methods to avoid include hell.
|
||||
|
||||
107
mm/userfaultfd.c
107
mm/userfaultfd.c
@@ -18,6 +18,7 @@
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/tlb.h>
|
||||
#include "internal.h"
|
||||
#include "swap.h"
|
||||
|
||||
static __always_inline
|
||||
bool validate_dst_vma(struct vm_area_struct *dst_vma, unsigned long dst_end)
|
||||
@@ -974,15 +975,13 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int move_swap_pte(struct mm_struct *mm,
|
||||
static int move_swap_pte(struct mm_struct *mm, struct vm_area_struct *dst_vma,
|
||||
unsigned long dst_addr, unsigned long src_addr,
|
||||
pte_t *dst_pte, pte_t *src_pte,
|
||||
pte_t orig_dst_pte, pte_t orig_src_pte,
|
||||
spinlock_t *dst_ptl, spinlock_t *src_ptl)
|
||||
spinlock_t *dst_ptl, spinlock_t *src_ptl,
|
||||
struct folio *src_folio)
|
||||
{
|
||||
if (!pte_swp_exclusive(orig_src_pte))
|
||||
return -EBUSY;
|
||||
|
||||
double_pt_lock(dst_ptl, src_ptl);
|
||||
|
||||
if (!pte_same(ptep_get(src_pte), orig_src_pte) ||
|
||||
@@ -991,6 +990,16 @@ static int move_swap_pte(struct mm_struct *mm,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* The src_folio resides in the swapcache, requiring an update to its
|
||||
* index and mapping to align with the dst_vma, where a swap-in may
|
||||
* occur and hit the swapcache after moving the PTE.
|
||||
*/
|
||||
if (src_folio) {
|
||||
page_move_anon_rmap(&src_folio->page, dst_vma);
|
||||
src_folio->index = linear_page_index(dst_vma, dst_addr);
|
||||
}
|
||||
|
||||
orig_src_pte = ptep_get_and_clear(mm, src_addr, src_pte);
|
||||
set_pte_at(mm, dst_addr, dst_pte, orig_src_pte);
|
||||
double_pt_unlock(dst_ptl, src_ptl);
|
||||
@@ -1037,6 +1046,7 @@ static int move_pages_pte(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd,
|
||||
__u64 mode)
|
||||
{
|
||||
swp_entry_t entry;
|
||||
struct swap_info_struct *si = NULL;
|
||||
pte_t orig_src_pte, orig_dst_pte;
|
||||
pte_t src_folio_pte;
|
||||
spinlock_t *src_ptl, *dst_ptl;
|
||||
@@ -1125,6 +1135,7 @@ retry:
|
||||
*/
|
||||
if (!src_folio) {
|
||||
struct folio *folio;
|
||||
bool locked;
|
||||
|
||||
/*
|
||||
* Pin the page while holding the lock to be sure the
|
||||
@@ -1144,14 +1155,28 @@ retry:
|
||||
goto out;
|
||||
}
|
||||
|
||||
locked = folio_trylock(folio);
|
||||
/*
|
||||
* We avoid waiting for folio lock with a raised
|
||||
* refcount for large folios because extra refcounts
|
||||
* will result in split_folio() failing later and
|
||||
* retrying. If multiple tasks are trying to move a
|
||||
* large folio we can end up livelocking.
|
||||
*/
|
||||
if (!locked && folio_test_large(folio)) {
|
||||
spin_unlock(src_ptl);
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
folio_get(folio);
|
||||
src_folio = folio;
|
||||
src_folio_pte = orig_src_pte;
|
||||
spin_unlock(src_ptl);
|
||||
|
||||
if (!folio_trylock(src_folio)) {
|
||||
pte_unmap(&orig_src_pte);
|
||||
pte_unmap(&orig_dst_pte);
|
||||
if (!locked) {
|
||||
pte_unmap(src_pte);
|
||||
pte_unmap(dst_pte);
|
||||
src_pte = dst_pte = NULL;
|
||||
/* now we can block and wait */
|
||||
folio_lock(src_folio);
|
||||
@@ -1167,8 +1192,8 @@ retry:
|
||||
/* at this point we have src_folio locked */
|
||||
if (folio_test_large(src_folio)) {
|
||||
/* split_folio() can block */
|
||||
pte_unmap(&orig_src_pte);
|
||||
pte_unmap(&orig_dst_pte);
|
||||
pte_unmap(src_pte);
|
||||
pte_unmap(dst_pte);
|
||||
src_pte = dst_pte = NULL;
|
||||
err = split_folio(src_folio);
|
||||
if (err)
|
||||
@@ -1193,8 +1218,8 @@ retry:
|
||||
goto out;
|
||||
}
|
||||
if (!anon_vma_trylock_write(src_anon_vma)) {
|
||||
pte_unmap(&orig_src_pte);
|
||||
pte_unmap(&orig_dst_pte);
|
||||
pte_unmap(src_pte);
|
||||
pte_unmap(dst_pte);
|
||||
src_pte = dst_pte = NULL;
|
||||
/* now we can block and wait */
|
||||
anon_vma_lock_write(src_anon_vma);
|
||||
@@ -1207,11 +1232,13 @@ retry:
|
||||
orig_dst_pte, orig_src_pte,
|
||||
dst_ptl, src_ptl, src_folio);
|
||||
} else {
|
||||
struct folio *folio = NULL;
|
||||
|
||||
entry = pte_to_swp_entry(orig_src_pte);
|
||||
if (non_swap_entry(entry)) {
|
||||
if (is_migration_entry(entry)) {
|
||||
pte_unmap(&orig_src_pte);
|
||||
pte_unmap(&orig_dst_pte);
|
||||
pte_unmap(src_pte);
|
||||
pte_unmap(dst_pte);
|
||||
src_pte = dst_pte = NULL;
|
||||
migration_entry_wait(mm, src_pmd, src_addr);
|
||||
err = -EAGAIN;
|
||||
@@ -1220,10 +1247,52 @@ retry:
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = move_swap_pte(mm, dst_addr, src_addr,
|
||||
dst_pte, src_pte,
|
||||
orig_dst_pte, orig_src_pte,
|
||||
dst_ptl, src_ptl);
|
||||
if (!pte_swp_exclusive(orig_src_pte)) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
si = get_swap_device(entry);
|
||||
if (unlikely(!si)) {
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* Verify the existence of the swapcache. If present, the folio's
|
||||
* index and mapping must be updated even when the PTE is a swap
|
||||
* entry. The anon_vma lock is not taken during this process since
|
||||
* the folio has already been unmapped, and the swap entry is
|
||||
* exclusive, preventing rmap walks.
|
||||
*
|
||||
* For large folios, return -EBUSY immediately, as split_folio()
|
||||
* also returns -EBUSY when attempting to split unmapped large
|
||||
* folios in the swapcache. This issue needs to be resolved
|
||||
* separately to allow proper handling.
|
||||
*/
|
||||
if (!src_folio)
|
||||
folio = filemap_get_folio(swap_address_space(entry),
|
||||
swp_offset(entry));
|
||||
if (!IS_ERR_OR_NULL(folio)) {
|
||||
if (folio_test_large(folio)) {
|
||||
err = -EBUSY;
|
||||
folio_put(folio);
|
||||
goto out;
|
||||
}
|
||||
src_folio = folio;
|
||||
src_folio_pte = orig_src_pte;
|
||||
if (!folio_trylock(src_folio)) {
|
||||
pte_unmap(src_pte);
|
||||
pte_unmap(dst_pte);
|
||||
src_pte = dst_pte = NULL;
|
||||
put_swap_device(si);
|
||||
si = NULL;
|
||||
/* now we can block and wait */
|
||||
folio_lock(src_folio);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
err = move_swap_pte(mm, dst_vma, dst_addr, src_addr, dst_pte, src_pte,
|
||||
orig_dst_pte, orig_src_pte, dst_ptl, src_ptl, src_folio);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -1240,6 +1309,8 @@ out:
|
||||
if (src_pte)
|
||||
pte_unmap(src_pte);
|
||||
mmu_notifier_invalidate_range_end(&range);
|
||||
if (si)
|
||||
put_swap_device(si);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -847,6 +847,7 @@ int folio_mapcount(struct folio *folio)
|
||||
ret -= nr;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(folio_mapcount);
|
||||
|
||||
/**
|
||||
* folio_copy - Copy the contents of one folio to another.
|
||||
|
||||
@@ -2709,6 +2709,8 @@ static void shrink_active_list(unsigned long nr_to_scan,
|
||||
}
|
||||
|
||||
trace_android_vh_page_referenced_check_bypass(folio, nr_to_scan, lru, &bypass);
|
||||
trace_android_vh_folio_referenced_check_bypass(folio, sc->priority,
|
||||
nr_to_scan, lru, &bypass);
|
||||
if (bypass)
|
||||
goto skip_folio_referenced;
|
||||
trace_android_vh_folio_trylock_set(folio);
|
||||
|
||||
@@ -118,12 +118,14 @@
|
||||
static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr);
|
||||
static void vsock_sk_destruct(struct sock *sk);
|
||||
static int vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
|
||||
static void vsock_close(struct sock *sk, long timeout);
|
||||
|
||||
/* Protocol family. */
|
||||
static struct proto vsock_proto = {
|
||||
.name = "AF_VSOCK",
|
||||
.owner = THIS_MODULE,
|
||||
.obj_size = sizeof(struct vsock_sock),
|
||||
.close = vsock_close,
|
||||
};
|
||||
|
||||
/* The default peer timeout indicates how long we will wait for a peer response
|
||||
@@ -333,7 +335,10 @@ EXPORT_SYMBOL_GPL(vsock_find_connected_socket);
|
||||
|
||||
void vsock_remove_sock(struct vsock_sock *vsk)
|
||||
{
|
||||
vsock_remove_bound(vsk);
|
||||
/* Transport reassignment must not remove the binding. */
|
||||
if (sock_flag(sk_vsock(vsk), SOCK_DEAD))
|
||||
vsock_remove_bound(vsk);
|
||||
|
||||
vsock_remove_connected(vsk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vsock_remove_sock);
|
||||
@@ -805,39 +810,44 @@ static bool sock_type_connectible(u16 type)
|
||||
|
||||
static void __vsock_release(struct sock *sk, int level)
|
||||
{
|
||||
if (sk) {
|
||||
struct sock *pending;
|
||||
struct vsock_sock *vsk;
|
||||
struct vsock_sock *vsk;
|
||||
struct sock *pending;
|
||||
|
||||
vsk = vsock_sk(sk);
|
||||
pending = NULL; /* Compiler warning. */
|
||||
vsk = vsock_sk(sk);
|
||||
pending = NULL; /* Compiler warning. */
|
||||
|
||||
/* When "level" is SINGLE_DEPTH_NESTING, use the nested
|
||||
* version to avoid the warning "possible recursive locking
|
||||
* detected". When "level" is 0, lock_sock_nested(sk, level)
|
||||
* is the same as lock_sock(sk).
|
||||
*/
|
||||
lock_sock_nested(sk, level);
|
||||
/* When "level" is SINGLE_DEPTH_NESTING, use the nested
|
||||
* version to avoid the warning "possible recursive locking
|
||||
* detected". When "level" is 0, lock_sock_nested(sk, level)
|
||||
* is the same as lock_sock(sk).
|
||||
*/
|
||||
lock_sock_nested(sk, level);
|
||||
|
||||
if (vsk->transport)
|
||||
vsk->transport->release(vsk);
|
||||
else if (sock_type_connectible(sk->sk_type))
|
||||
vsock_remove_sock(vsk);
|
||||
/* Indicate to vsock_remove_sock() that the socket is being released and
|
||||
* can be removed from the bound_table. Unlike transport reassignment
|
||||
* case, where the socket must remain bound despite vsock_remove_sock()
|
||||
* being called from the transport release() callback.
|
||||
*/
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
|
||||
sock_orphan(sk);
|
||||
sk->sk_shutdown = SHUTDOWN_MASK;
|
||||
if (vsk->transport)
|
||||
vsk->transport->release(vsk);
|
||||
else if (sock_type_connectible(sk->sk_type))
|
||||
vsock_remove_sock(vsk);
|
||||
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
sock_orphan(sk);
|
||||
sk->sk_shutdown = SHUTDOWN_MASK;
|
||||
|
||||
/* Clean up any sockets that never were accepted. */
|
||||
while ((pending = vsock_dequeue_accept(sk)) != NULL) {
|
||||
__vsock_release(pending, SINGLE_DEPTH_NESTING);
|
||||
sock_put(pending);
|
||||
}
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
|
||||
release_sock(sk);
|
||||
sock_put(sk);
|
||||
/* Clean up any sockets that never were accepted. */
|
||||
while ((pending = vsock_dequeue_accept(sk)) != NULL) {
|
||||
__vsock_release(pending, SINGLE_DEPTH_NESTING);
|
||||
sock_put(pending);
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
sock_put(sk);
|
||||
}
|
||||
|
||||
static void vsock_sk_destruct(struct sock *sk)
|
||||
@@ -914,9 +924,22 @@ void vsock_data_ready(struct sock *sk)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vsock_data_ready);
|
||||
|
||||
/* Dummy callback required by sockmap.
|
||||
* See unconditional call of saved_close() in sock_map_close().
|
||||
*/
|
||||
static void vsock_close(struct sock *sk, long timeout)
|
||||
{
|
||||
}
|
||||
|
||||
static int vsock_release(struct socket *sock)
|
||||
{
|
||||
__vsock_release(sock->sk, 0);
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
sk->sk_prot->close(sk, 0);
|
||||
__vsock_release(sk, 0);
|
||||
sock->sk = NULL;
|
||||
sock->state = SS_FREE;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user