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:

* 1c9aeb1ce3 Merge tag 'android14-6.1.129_r00' into android14-6.1
* b18db21117 ANDROID: GKI: Update rockchip symbols for drm driver.
* f628136006 ANDROID: ABI: Update pixel symbol list
* 2fb96ec85c ANDROID: vendor_hook: add vendor hook on calculate_totalreserve_pages
* 5145d15773 ANDROID: GKI: update symbol list file for xiaomi
* 2f4537ba6c ANDROID: vendor_hooks: Skip pages with high memory pressure in shrink_active_list
* da6a42c111 FROMGIT: mm/page_alloc: add trace event for totalreserve_pages calculation
* 95baed1663 BACKPORT: FROMGIT: mm/page_alloc: add trace event for per-zone lowmem reserve setup
* 9d6305174c BACKPORT: FROMGIT: mm/page_alloc: add trace event for per-zone watermark setup
* 7da329f7cf ANDROID: Update the ABI symbol list
* d3b0aaa092 ANDROID: Add EXPORT_SYMBOL_GPL for folio_mapcount
* 6bd3e435f2 UPSTREAM: f2fs: fix inconsistent dirty state of atomic file
* 2afd0800a7 UPSTREAM: net: avoid race between device unregistration and ethnl ops
* 92ada4b4c2 UPSTREAM: pfifo_tail_enqueue: Drop new packet when sch->limit == 0
* cd0ebcd175 UPSTREAM: vsock: Orphan socket after transport release
* 7f11cc02d9 UPSTREAM: vsock: Keep the binding until socket destruction
* e2647b0fb4 UPSTREAM: bpf, vsock: Invoke proto::close on close()
* cfa792a776 FROMGIT: f2fs: fix to avoid atomicity corruption of atomic file
* f3c4686f77 ANDROID: abi_gki_aarch64_qcom: Add xas_load
* 33c9d4844a ANDROID: Update the ABI symbol list
* 0ad7fae66c ANDROID: printk: add vendor hook to logging during hibernation
* 4da91a8e56 BACKPORT: FROMGIT: f2fs: fix to avoid running out of free segments
* 64560e780e BACKPORT: FROMGIT: f2fs: fix to avoid panic once fallocation fails for pinfile
* 27895588a2 BACKPORT: f2fs: compress: fix inconsistent update of i_blocks in release_compress_blocks and reserve_compress_blocks
* 70d032fba5 ANDROID: GKI: Add KMI symbol list for zebra
* efd0bedd2c ANDROID: GKI: Update rockchip symbols for drm driver.
* 69a6dfc9c3 ANDROID: GKI: Update symbol list for mtk
* 9bcabbda67 ANDROID: userfaultfd: add MOVE ioctl mode to confirm bug-fixes
* 8d8d44ff91 FROMGIT: userfaultfd: fix PTE unmapping stack-allocated PTE copies
* af439accc7 FROMGIT: userfaultfd: do not block on locking a large folio with raised refcount
* 7d6124b604 FROMGIT: BACKPORT: mm: fix kernel BUG when userfaultfd_move encounters swapcache
* 44db4837f7 ANDROID: Update the ABI symbol list
* 50eddb3fc9 FROMGIT: f2fs: set highest IO priority for checkpoint thread
* 471a10d3af ANDROID: mm/memfd-ashmem-shim: Fix variable length array usage
* 6b227a1f74 ANDROID: GKI: Update symbol list for xiaomi
* eaffa3e341 ANDROID: mm: add a new vendor hook in filemap_map_pages
* fa3cc11118 ANDROID: GKI: Enable CONFIG_MEMFD_ASHMEM_SHIM
* 6355ece3ca ANDROID: mm: shmem: Use memfd-ashmem-shim ioctl handler
* 004c31328a ANDROID: mm/memfd-ashmem-shim: Introduce shim layer
* b4fef39187 ANDROID: ashmem: Add toggle to ignore requests to deny PROT_EXEC mappings
* ef10c0ef7d ANDROID: ashmem: Add toggle to ignore requests to deny PROT_READ mappings
* 9f6b96dfca ANDROID: ashmem: Add support for disabling unpinning feature
* 4deb2cd703 ANDROID: Update the ABI symbol list
* 75c1d11b88 ANDROID: swapfile: Add EXPORT_SYMBOL_GPL for page_swap_info
* f27efe75fc UPSTREAM: io_uring: fix io_req_prep_async with provided buffers
* 719cffaab0 ANDROID: GKI: Update symbol list for BCMSTB
* 6ad8aa12e1 ANDROID: abi_gki_aarch64_qcom: Update symbol list
* 45755ee7b6 ANDROID: of: add export symbol for of_update_property
* cf7683f719 ANDROID: GKI: Update oplus symbol list

Change-Id: I8da40828d5179139546e9bc8b15efdbae9bc57de
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-03-26 14:56:23 +00:00
41 changed files with 1547 additions and 88 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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)) {

View File

@@ -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.
*/

View File

@@ -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 */

View File

@@ -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>

View File

@@ -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));

View File

@@ -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

View File

@@ -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));

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View 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
View 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
View 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 */

View File

@@ -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);
}

View File

@@ -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 = {

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;