Merge branch 'android14-6.1' into branch 'android14-6.1-lts'

This catches the android14-6.1-lts branch up with the latest changes and
abi updates.  Included in here are the following commits:

07775f9683 ANDROID: GKI: Add symbols for rockchip sata
f44d373b32 ANDROID: sched: Add trace_android_rvh_setscheduler
efa8f34b5a ANDROID: Update the ABI symbol list
cee8ebf7c5 ANDROID: GKI: build damon for monitoring virtual address spaces
31c59d59c7 UPSTREAM: mm/damon/sysfs-schemes: handle tried region directory allocation failure
1cedfc05e9 UPSTREAM: mm/damon/sysfs-schemes: handle tried regions sysfs directory allocation failure
7fbeab3c65 UPSTREAM: mm/damon/sysfs: check error from damon_sysfs_update_target()
606444fd06 UPSTREAM: mm/damon/sysfs: eliminate potential uninitialized variable warning
c132d077eb UPSTREAM: mm/damon/sysfs: update monitoring target regions for online input commit
6b7c4cc262 UPSTREAM: mm/damon/sysfs: remove requested targets when online-commit inputs
1e19db10e7 UPSTREAM: mm/damon/sysfs: avoid empty scheme tried regions for large apply interval
c194e597cb UPSTREAM: mm/damon/sysfs-schemes: do not update tried regions more than one DAMON snapshot
f5a0a8bc43 UPSTREAM: mm/damon/sysfs: check DAMOS regions update progress from before_terminate()
b46391e092 UPSTREAM: mm/damon/sysfs: implement a command for updating only schemes tried total bytes
7d48e19f74 UPSTREAM: mm/damon/sysfs-schemes: implement DAMOS tried total bytes file
a548d90994 UPSTREAM: mm/damon/ops-common: refactor to use {pte|pmd}p_clear_young_notify()
ea215c9a10 UPSTREAM: mm/damon/core: skip apply schemes if empty
3ca21ef5fa UPSTREAM: mm/damon: use kstrtobool() instead of strtobool()
5bf7b56860 UPSTREAM: mm/damon/sysfs-schemes: implement DAMOS-tried regions clear command
80ccab9b0e UPSTREAM: mm/damon/sysfs: implement DAMOS tried regions update command
3421250b35 UPSTREAM: mm/damon/sysfs-schemes: implement scheme region directory
b4c34cc168 UPSTREAM: mm/damon/sysfs-schemes: implement schemes/tried_regions directory
b5d1f3576b UPSTREAM: mm/damon/core: add a callback for scheme target regions check
6547a97f32 UPSTREAM: mm/damon/lru_sort: enable and disable synchronously
540e9b850d UPSTREAM: mm/damon/reclaim: enable and disable synchronously
4e2d3f8e31 UPSTREAM: mm/damon/{reclaim,lru_sort}: remove unnecessarily included headers
3c0bc73f6e UPSTREAM: mm/damon/modules: deduplicate init steps for DAMON context setup
67ef7b0f42 UPSTREAM: mm/damon/sysfs: split out schemes directory implementation to separate file
0b17df8a4f UPSTREAM: mm/damon/sysfs: split out kdamond-independent schemes stats update logic into a new function
a45dff567c UPSTREAM: mm/damon/sysfs: move unsigned long range directory to common module
c5038d80ce UPSTREAM: mm/damon/sysfs: move sysfs_lock to common module
b7fc8d59a5 UPSTREAM: mm/damon/sysfs: remove parameters of damon_sysfs_region_alloc()
19364f11a4 UPSTREAM: mm/damon/sysfs: use damon_addr_range for region's start and end values
b6e6b1dbf8 UPSTREAM: mm/damon/core: split out scheme quota adjustment logic into a new function
43475d9708 UPSTREAM: mm/damon/core: split out scheme stat update logic into a new function
0b0a43029e UPSTREAM: mm/damon/core: split damos application logic into a new function
6c7495f04a UPSTREAM: mm/damon/core: split out DAMOS-charged region skip logic into a new function
ac1031618a ANDROID: Snapshot Mainline's version of checkpatch.pl
4fa87d4d8f ANDROID: KVM: arm64: Skip prefaulting ptes which will be modified later
fbc707442c ANDROID: KVM: arm64: Introduce module_change_host_prot_range
fd720ebc6a ANDROID: KVM: arm64: Relax checks in module_change_host_page_prot
f082d22541 ANDROID: KVM: arm64: Optimise module_change_host_page_prot
01dd8c280b ANDROID: KVM: arm64: Prefault entries when splitting a block mapping
cc653d701f ANDROID: virt: gunyah: Zero state_data after vcpu_run
cc294d9503 ANDROID: Update the ABI symbol list
956a0d3998 ANDROID: fs: Add vendor hooks for ep_create_wakeup_source & timerfd_create
d8d2b95fd0 ANDROID: ABI: update symbol list for galaxy
bcc758eed7 Reapply "binder: fix UAF caused by faulty buffer cleanup"
b2b3a1e6d1 UPSTREAM: x86/sev: Check for user-space IOIO pointing to kernel space
62b97630d4 UPSTREAM: x86/sev: Check IOBM for IOIO exceptions from user-space
071c14698c FROMGIT: usb: typec: tcpm: skip checking port->send_discover in PD3.0
a9567a35d0 ANDROID: arm64: Disable workaround for CPU errata 2441007 and 2441009

Change-Id: Icbda2fae389ea4c2e7230821c59ac0380a35d756
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman 2023-12-19 19:04:44 +00:00
commit a01e106f08
33 changed files with 3040 additions and 1489 deletions

File diff suppressed because it is too large Load Diff

View File

@ -274,6 +274,8 @@
sched_clock
sched_show_task
scnprintf
scsi_device_quiesce
scsi_device_resume
seq_hex_dump
seq_lseek
seq_printf

View File

@ -544,12 +544,16 @@
dma_fence_array_create
dma_fence_context_alloc
dma_fence_default_wait
dma_fence_enable_sw_signaling
dma_fence_get_status
dma_fence_init
dma_fence_release
dma_fence_remove_callback
dma_fence_signal
dma_fence_signal_locked
dma_fence_unwrap_first
__dma_fence_unwrap_merge
dma_fence_unwrap_next
dma_fence_wait_timeout
dma_free_attrs
dma_free_pages
@ -1162,7 +1166,10 @@
kernel_param_lock
kernel_param_unlock
kernel_restart
kernfs_find_and_get_ns
kernfs_notify
kernfs_path_from_node
kernfs_put
key_create_or_update
key_put
keyring_alloc
@ -2150,6 +2157,7 @@
thermal_zone_get_temp
thermal_zone_get_zone_by_name
thread_group_cputime_adjusted
tick_nohz_get_idle_calls_cpu
time64_to_tm
topology_update_thermal_pressure
_totalram_pages
@ -2209,6 +2217,7 @@
__traceiter_android_vh_dup_task_struct
__traceiter_android_vh_early_resume_begin
__traceiter_android_vh_enable_thermal_genl_check
__traceiter_android_vh_ep_create_wakeup_source
__traceiter_android_vh_filemap_get_folio
__traceiter_android_vh_ipi_stop
__traceiter_android_vh_meminfo_proc_show
@ -2222,6 +2231,7 @@
__traceiter_android_vh_setscheduler_uclamp
__traceiter_android_vh_si_meminfo_adjust
__traceiter_android_vh_sysrq_crash
__traceiter_android_vh_timerfd_create
__traceiter_android_vh_typec_store_partner_src_caps
__traceiter_android_vh_typec_tcpci_override_toggling
__traceiter_android_vh_typec_tcpm_get_timer
@ -2316,6 +2326,7 @@
__tracepoint_android_vh_dup_task_struct
__tracepoint_android_vh_early_resume_begin
__tracepoint_android_vh_enable_thermal_genl_check
__tracepoint_android_vh_ep_create_wakeup_source
__tracepoint_android_vh_filemap_get_folio
__tracepoint_android_vh_ipi_stop
__tracepoint_android_vh_meminfo_proc_show
@ -2329,6 +2340,7 @@
__tracepoint_android_vh_setscheduler_uclamp
__tracepoint_android_vh_si_meminfo_adjust
__tracepoint_android_vh_sysrq_crash
__tracepoint_android_vh_timerfd_create
__tracepoint_android_vh_typec_store_partner_src_caps
__tracepoint_android_vh_typec_tcpci_override_toggling
__tracepoint_android_vh_typec_tcpm_get_timer

View File

@ -2,6 +2,7 @@
# commonly used symbols
add_timer
alloc_chrdev_region
alloc_etherdev_mqs
alloc_iova_fast
__alloc_pages
__alloc_skb
@ -827,9 +828,25 @@
param_ops_int
param_ops_string
param_ops_uint
param_ops_ulong
pci_disable_device
pci_disable_link_state
pcie_capability_clear_and_set_word
pci_find_capability
pcim_enable_device
pcim_iomap_table
pcim_pin_device
pci_read_config_byte
pci_read_config_dword
pci_read_config_word
__pci_register_driver
pci_restore_state
pci_save_state
pci_set_master
pci_set_power_state
pci_unregister_driver
pci_write_config_dword
pci_write_config_word
__per_cpu_offset
perf_trace_buf_alloc
perf_trace_run_bpf_submit
@ -1023,7 +1040,11 @@
sched_set_fifo
schedule
schedule_timeout
schedule_timeout_uninterruptible
scnprintf
scsi_command_size_tbl
scsi_device_get
scsi_device_put
__sdhci_add_host
sdhci_cleanup_host
sdhci_enable_clk
@ -1325,6 +1346,7 @@
vunmap
vzalloc
wait_for_completion
wait_for_completion_interruptible
wait_for_completion_timeout
__wake_up
wake_up_process
@ -1346,15 +1368,23 @@
skcipher_walk_aead_decrypt
skcipher_walk_aead_encrypt
# required by ahci.ko
pci_alloc_irq_vectors_affinity
pci_free_irq_vectors
pci_intx
pci_irq_vector
pci_match_id
pcim_iomap_regions_request_all
sysfs_add_file_to_group
sysfs_remove_file_from_group
# required by analogix_dp.ko
drm_atomic_get_old_connector_for_encoder
# required by aspm_ext.ko
pci_find_capability
pci_find_ext_capability
# required by bcmdhd.ko
alloc_etherdev_mqs
cpu_bit_bitmap
down_interruptible
down_timeout
@ -1873,6 +1903,60 @@
# required by ledtrig-heartbeat.ko
avenrun
# required by libahci.ko
__printk_ratelimit
# required by libahci_platform.ko
reset_control_rearm
# required by libata.ko
async_schedule_node
async_synchronize_cookie
attribute_container_register
attribute_container_unregister
autoremove_wake_function
blk_abort_request
blk_queue_max_hw_sectors
blk_queue_max_segments
blk_queue_update_dma_alignment
blk_queue_update_dma_pad
glob_match
pci_bus_type
pcim_iomap_regions
prepare_to_wait
__scsi_add_device
scsi_add_host_with_dma
scsi_build_sense
scsi_change_queue_depth
scsi_check_sense
scsi_device_set_state
scsi_done
scsi_eh_finish_cmd
scsi_eh_flush_done_q
scsi_execute_cmd
__scsi_format_command
scsi_host_alloc
scsi_host_put
scsi_remove_device
scsi_remove_host
scsi_rescan_device
scsi_schedule_eh
scsi_sense_desc_find
scsi_set_sense_field_pointer
scsi_set_sense_information
sdev_evt_send_simple
system_entering_hibernation
trace_seq_printf
trace_seq_putc
transport_add_device
transport_class_register
transport_class_unregister
transport_configure_device
transport_destroy_device
transport_remove_device
transport_setup_device
vscnprintf
# required by mac80211.ko
alloc_netdev_mqs
__alloc_percpu_gfp

View File

@ -642,7 +642,6 @@ config ARM64_WORKAROUND_REPEAT_TLBI
config ARM64_ERRATUM_2441007
bool "Cortex-A55: Completion of affected memory accesses might not be guaranteed by completion of a TLBI"
default y
select ARM64_WORKAROUND_REPEAT_TLBI
help
This option adds a workaround for ARM Cortex-A55 erratum #2441007.
@ -881,7 +880,6 @@ config ARM64_ERRATUM_2224489
config ARM64_ERRATUM_2441009
bool "Cortex-A510: Completion of affected memory accesses might not be guaranteed by completion of a TLBI"
default y
select ARM64_WORKAROUND_REPEAT_TLBI
help
This option adds a workaround for ARM Cortex-A510 erratum #2441009.

View File

@ -123,6 +123,9 @@ CONFIG_ANON_VMA_NAME=y
CONFIG_USERFAULTFD=y
CONFIG_LRU_GEN=y
CONFIG_LRU_GEN_ENABLED=y
CONFIG_DAMON=y
CONFIG_DAMON_VADDR=y
CONFIG_DAMON_SYSFS=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y

View File

@ -153,7 +153,8 @@ struct pkvm_module_ops {
void* (*hyp_va)(phys_addr_t phys);
unsigned long (*kern_hyp_va)(unsigned long x);
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_USE(1, int (*host_stage2_mod_prot_range)(u64 pfn, enum kvm_pgtable_prot prot, u64 nr_pages));
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
ANDROID_KABI_RESERVE(4);

View File

@ -104,6 +104,7 @@ int refill_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages,
struct kvm_hyp_memcache *host_mc);
int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot);
int module_change_host_page_prot_range(u64 pfn, enum kvm_pgtable_prot prot, u64 nr_pages);
void destroy_hyp_vm_pgt(struct pkvm_hyp_vm *vm);
void drain_hyp_pool(struct pkvm_hyp_vm *vm, struct kvm_hyp_memcache *mc);

View File

@ -2008,77 +2008,80 @@ int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages)
return ret;
}
static int restrict_host_page_perms(u64 addr, kvm_pte_t pte, u32 level, enum kvm_pgtable_prot prot)
{
int ret = 0;
/* XXX: optimize ... */
if (kvm_pte_valid(pte) && (level == KVM_PGTABLE_MAX_LEVELS - 1))
ret = kvm_pgtable_stage2_unmap(&host_mmu.pgt, addr, PAGE_SIZE);
if (!ret)
ret = host_stage2_idmap_locked(addr, PAGE_SIZE, prot, false);
return ret;
}
#define MODULE_PROT_ALLOWLIST (KVM_PGTABLE_PROT_RWX | \
KVM_PGTABLE_PROT_DEVICE |\
KVM_PGTABLE_PROT_NC | \
KVM_PGTABLE_PROT_PXN | \
KVM_PGTABLE_PROT_UXN)
int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot)
int module_change_host_page_prot_range(u64 pfn, enum kvm_pgtable_prot prot, u64 nr_pages)
{
u64 addr = hyp_pfn_to_phys(pfn);
u64 i, addr = hyp_pfn_to_phys(pfn);
u64 end = addr + nr_pages * PAGE_SIZE;
struct hyp_page *page = NULL;
kvm_pte_t pte;
u32 level;
struct kvm_mem_range range;
bool is_mmio;
int ret;
if ((prot & MODULE_PROT_ALLOWLIST) != prot)
return -EINVAL;
is_mmio = !find_mem_range(addr, &range);
if (end > range.end) {
/* Specified range not in a single mmio or memory block. */
return -EPERM;
}
host_lock_component();
ret = kvm_pgtable_get_leaf(&host_mmu.pgt, addr, &pte, &level);
if (ret)
goto unlock;
/*
* There is no hyp_vmemmap covering MMIO regions, which makes tracking
* of module-owned MMIO regions hard, so we trust the modules not to
* mess things up.
*/
if (!addr_is_memory(addr))
if (is_mmio)
goto update;
ret = -EPERM;
/* Range is memory: we can track module ownership. */
page = hyp_phys_to_page(addr);
/*
* Modules can only relax permissions of pages they own, and restrict
* permissions of pristine pages.
* Modules can only modify pages they already own, and pristine host
* pages. The entire range must be consistently one or the other.
*/
if (prot == KVM_PGTABLE_PROT_RWX) {
if (!(page->flags & MODULE_OWNED_PAGE))
if (page->flags & MODULE_OWNED_PAGE) {
/* The entire range must be module-owned. */
ret = -EPERM;
for (i = 1; i < nr_pages; i++) {
if (!(page[i].flags & MODULE_OWNED_PAGE))
goto unlock;
}
} else {
/* The entire range must be pristine. */
ret = __host_check_page_state_range(
addr, nr_pages << PAGE_SHIFT, PKVM_PAGE_OWNED);
if (ret)
goto unlock;
} else if (host_get_page_state(pte, addr) != PKVM_PAGE_OWNED) {
goto unlock;
}
update:
if (prot == default_host_prot(!!page))
ret = host_stage2_set_owner_locked(addr, PAGE_SIZE, PKVM_ID_HOST);
else if (!prot)
ret = host_stage2_set_owner_locked(addr, PAGE_SIZE, PKVM_ID_PROTECTED);
else
ret = restrict_host_page_perms(addr, pte, level, prot);
if (!prot) {
ret = host_stage2_set_owner_locked(
addr, nr_pages << PAGE_SHIFT, PKVM_ID_PROTECTED);
} else {
ret = host_stage2_idmap_locked(
addr, nr_pages << PAGE_SHIFT, prot, false);
}
if (ret || !page)
if (WARN_ON(ret) || !page)
goto unlock;
if (prot != KVM_PGTABLE_PROT_RWX)
hyp_phys_to_page(addr)->flags |= MODULE_OWNED_PAGE;
else
hyp_phys_to_page(addr)->flags &= ~MODULE_OWNED_PAGE;
for (i = 0; i < nr_pages; i++) {
if (prot != KVM_PGTABLE_PROT_RWX)
page[i].flags |= MODULE_OWNED_PAGE;
else
page[i].flags &= ~MODULE_OWNED_PAGE;
}
unlock:
host_unlock_component();
@ -2086,6 +2089,11 @@ int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot)
return ret;
}
int module_change_host_page_prot(u64 pfn, enum kvm_pgtable_prot prot)
{
return module_change_host_page_prot_range(pfn, prot, 1);
}
int hyp_pin_shared_mem(void *from, void *to)
{
u64 cur, start = ALIGN_DOWN((u64)from, PAGE_SIZE);

View File

@ -115,6 +115,7 @@ const struct pkvm_module_ops module_ops = {
.hyp_pa = hyp_virt_to_phys,
.hyp_va = hyp_phys_to_virt,
.kern_hyp_va = __kern_hyp_va,
.host_stage2_mod_prot_range = module_change_host_page_prot_range,
};
int __pkvm_init_module(void *module_init)

View File

@ -645,8 +645,13 @@ enum kvm_pgtable_prot kvm_pgtable_stage2_pte_prot(kvm_pte_t pte)
return prot;
}
static bool stage2_pte_needs_update(kvm_pte_t old, kvm_pte_t new)
static bool stage2_pte_needs_update(struct kvm_pgtable *pgt,
kvm_pte_t old, kvm_pte_t new)
{
/* Following filter logic applies only to guest stage-2 entries. */
if (pgt->flags & KVM_PGTABLE_S2_IDMAP)
return true;
if (!kvm_pte_valid(old) || !kvm_pte_valid(new))
return true;
@ -715,12 +720,15 @@ static int stage2_map_walker_try_leaf(u64 addr, u64 end, u32 level,
new = data->annotation;
/*
* Skip updating the PTE if we are trying to recreate the exact
* same mapping or only change the access permissions. Instead,
* the vCPU will exit one more time from guest if still needed
* and then go through the path of relaxing permissions.
* Skip updating a guest PTE if we are trying to recreate the exact
* same mapping or change only the access permissions. Instead,
* the vCPU will exit one more time from the guest if still needed
* and then go through the path of relaxing permissions. This applies
* only to guest PTEs; Host PTEs are unconditionally updated. The
* host cannot livelock because the abort handler has done prior
* checks before calling here.
*/
if (!stage2_pte_needs_update(old, new))
if (!stage2_pte_needs_update(pgt, old, new))
return -EAGAIN;
if (pte_ops->pte_is_counted_cb(old, level))
@ -775,6 +783,30 @@ static int stage2_map_walk_table_pre(u64 addr, u64 end, u32 level,
return 0;
}
static void stage2_map_prefault_idmap(struct kvm_pgtable_pte_ops *pte_ops,
u64 addr, u64 end, u32 level,
kvm_pte_t *ptep, kvm_pte_t block_pte)
{
u64 pa, granule;
int i;
WARN_ON(pte_ops->pte_is_counted_cb(block_pte, level-1));
if (!kvm_pte_valid(block_pte))
return;
pa = ALIGN_DOWN(addr, kvm_granule_size(level-1));
granule = kvm_granule_size(level);
for (i = 0; i < PTRS_PER_PTE; ++i, ++ptep, pa += granule) {
kvm_pte_t pte = kvm_init_valid_leaf_pte(pa, block_pte, level);
/* Skip ptes in the range being modified by the caller. */
if ((pa < addr) || (pa >= end)) {
/* We can write non-atomically: ptep isn't yet live. */
*ptep = pte;
}
}
}
static int stage2_map_walk_leaf(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
struct stage2_map_data *data)
{
@ -805,6 +837,11 @@ static int stage2_map_walk_leaf(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
if (!childp)
return -ENOMEM;
if (pgt->flags & KVM_PGTABLE_S2_IDMAP) {
stage2_map_prefault_idmap(pte_ops, addr, end, level + 1,
childp, pte);
}
/*
* If we've run into an existing block mapping then replace it with
* a table. Accesses beyond 'end' that fall within the new table

View File

@ -118,6 +118,9 @@ CONFIG_ANON_VMA_NAME=y
CONFIG_USERFAULTFD=y
CONFIG_LRU_GEN=y
CONFIG_LRU_GEN_ENABLED=y
CONFIG_DAMON=y
CONFIG_DAMON_VADDR=y
CONFIG_DAMON_SYSFS=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y

View File

@ -2127,24 +2127,23 @@ static void binder_deferred_fd_close(int fd)
static void binder_transaction_buffer_release(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_buffer *buffer,
binder_size_t failed_at,
binder_size_t off_end_offset,
bool is_failure)
{
int debug_id = buffer->debug_id;
binder_size_t off_start_offset, buffer_offset, off_end_offset;
binder_size_t off_start_offset, buffer_offset;
binder_debug(BINDER_DEBUG_TRANSACTION,
"%d buffer release %d, size %zd-%zd, failed at %llx\n",
proc->pid, buffer->debug_id,
buffer->data_size, buffer->offsets_size,
(unsigned long long)failed_at);
(unsigned long long)off_end_offset);
if (buffer->target_node)
binder_dec_node(buffer->target_node, 1, 0);
off_start_offset = ALIGN(buffer->data_size, sizeof(void *));
off_end_offset = is_failure && failed_at ? failed_at :
off_start_offset + buffer->offsets_size;
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
buffer_offset += sizeof(binder_size_t)) {
struct binder_object_header *hdr;
@ -2304,6 +2303,21 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
}
}
/* Clean up all the objects in the buffer */
static inline void binder_release_entire_buffer(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_buffer *buffer,
bool is_failure)
{
binder_size_t off_end_offset;
off_end_offset = ALIGN(buffer->data_size, sizeof(void *));
off_end_offset += buffer->offsets_size;
binder_transaction_buffer_release(proc, thread, buffer,
off_end_offset, is_failure);
}
static int binder_translate_binder(struct flat_binder_object *fp,
struct binder_transaction *t,
struct binder_thread *thread)
@ -3013,7 +3027,7 @@ static int binder_proc_transaction(struct binder_transaction *t,
t_outdated->buffer = NULL;
buffer->transaction = NULL;
trace_binder_transaction_update_buffer_release(buffer);
binder_transaction_buffer_release(proc, NULL, buffer, 0, 0);
binder_release_entire_buffer(proc, NULL, buffer, false);
binder_alloc_free_buf(&proc->alloc, buffer);
kfree(t_outdated);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
@ -4004,7 +4018,7 @@ binder_free_buf(struct binder_proc *proc,
binder_node_inner_unlock(buf_node);
}
trace_binder_transaction_buffer_release(buffer);
binder_transaction_buffer_release(proc, thread, buffer, 0, is_failure);
binder_release_entire_buffer(proc, thread, buffer, is_failure);
binder_alloc_free_buf(&proc->alloc, buffer);
}

View File

@ -26,6 +26,7 @@
#include <trace/hooks/printk.h>
#include <trace/hooks/epoch.h>
#include <trace/hooks/cpufreq.h>
#include <trace/hooks/fs.h>
#include <trace/hooks/preemptirq.h>
#include <trace/hooks/ftrace_dump.h>
#include <trace/hooks/ufshcd.h>
@ -365,3 +366,5 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sd_update_bus_speed_mode);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_slab_folio_alloced);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_kmalloc_large_alloced);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_netlink_poll);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_ep_create_wakeup_source);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_timerfd_create);

View File

@ -2855,7 +2855,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
PD_MSG_CTRL_NOT_SUPP,
NONE_AMS);
} else {
if (port->send_discover) {
if (port->send_discover && port->negotiated_rev < PD_REV30) {
tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
break;
}
@ -2871,7 +2871,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
PD_MSG_CTRL_NOT_SUPP,
NONE_AMS);
} else {
if (port->send_discover) {
if (port->send_discover && port->negotiated_rev < PD_REV30) {
tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
break;
}
@ -2880,7 +2880,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
}
break;
case PD_CTRL_VCONN_SWAP:
if (port->send_discover) {
if (port->send_discover && port->negotiated_rev < PD_REV30) {
tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
break;
}

View File

@ -196,6 +196,7 @@ static int gh_vcpu_run(struct gh_vcpu *vcpu)
}
gh_error = gh_hypercall_vcpu_run(vcpu->rsc->capid, state_data, &vcpu_run_resp);
memset(state_data, 0, sizeof(state_data));
if (gh_error == GH_ERROR_OK) {
switch (vcpu_run_resp.state) {
case GH_VCPU_STATE_READY:

View File

@ -39,6 +39,8 @@
#include <linux/rculist.h>
#include <net/busy_poll.h>
#include <trace/hooks/fs.h>
/*
* LOCKING:
* There are three level of locking required by epoll :
@ -1373,15 +1375,20 @@ static int ep_create_wakeup_source(struct epitem *epi)
{
struct name_snapshot n;
struct wakeup_source *ws;
char ws_name[64];
strlcpy(ws_name, "eventpoll", sizeof(ws_name));
trace_android_vh_ep_create_wakeup_source(ws_name, sizeof(ws_name));
if (!epi->ep->ws) {
epi->ep->ws = wakeup_source_register(NULL, "eventpoll");
epi->ep->ws = wakeup_source_register(NULL, ws_name);
if (!epi->ep->ws)
return -ENOMEM;
}
take_dentry_name_snapshot(&n, epi->ffd.file->f_path.dentry);
ws = wakeup_source_register(NULL, n.name.name);
strlcpy(ws_name, n.name.name, sizeof(ws_name));
trace_android_vh_ep_create_wakeup_source(ws_name, sizeof(ws_name));
ws = wakeup_source_register(NULL, ws_name);
release_dentry_name_snapshot(&n);
if (!ws)

View File

@ -28,6 +28,8 @@
#include <linux/rcupdate.h>
#include <linux/time_namespace.h>
#include <trace/hooks/fs.h>
struct timerfd_ctx {
union {
struct hrtimer tmr;
@ -407,6 +409,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
{
int ufd;
struct timerfd_ctx *ctx;
char file_name_buf[32];
/* Check the TFD_* constants for consistency. */
BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
@ -443,7 +446,9 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
ctx->moffs = ktime_mono_to_real(0);
ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
strlcpy(file_name_buf, "[timerfd]", sizeof(file_name_buf));
trace_android_vh_timerfd_create(file_name_buf, sizeof(file_name_buf));
ufd = anon_inode_getfd(file_name_buf, &timerfd_fops, ctx,
O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
if (ufd < 0)
kfree(ctx);
@ -451,7 +456,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
return ufd;
}
static int do_timerfd_settime(int ufd, int flags,
static int do_timerfd_settime(int ufd, int flags,
const struct itimerspec64 *new,
struct itimerspec64 *old)
{

View File

@ -357,6 +357,7 @@ struct damon_operations {
* @after_wmarks_check: Called after each schemes' watermarks check.
* @after_sampling: Called after each sampling.
* @after_aggregation: Called after each aggregation.
* @before_damos_apply: Called before applying DAMOS action.
* @before_terminate: Called before terminating the monitoring.
* @private: User private data.
*
@ -385,6 +386,10 @@ struct damon_callback {
int (*after_wmarks_check)(struct damon_ctx *context);
int (*after_sampling)(struct damon_ctx *context);
int (*after_aggregation)(struct damon_ctx *context);
int (*before_damos_apply)(struct damon_ctx *context,
struct damon_target *target,
struct damon_region *region,
struct damos *scheme);
void (*before_terminate)(struct damon_ctx *context);
};

23
include/trace/hooks/fs.h Normal file
View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM fs
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH trace/hooks
#if !defined(_TRACE_HOOK_FS_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HOOK_FS_H
#include <trace/hooks/vendor_hooks.h>
DECLARE_HOOK(android_vh_ep_create_wakeup_source,
TP_PROTO(char *name, int len),
TP_ARGS(name, len));
DECLARE_HOOK(android_vh_timerfd_create,
TP_PROTO(char *name, int len),
TP_ARGS(name, len));
#endif /* _TRACE_HOOK_FS_H */
/* This part must be outside protection */
#include <trace/define_trace.h>

View File

@ -7841,6 +7841,7 @@ static int __sched_setscheduler(struct task_struct *p,
if (!(attr->sched_flags & SCHED_FLAG_KEEP_PARAMS)) {
__setscheduler_params(p, attr);
__setscheduler_prio(p, newprio);
trace_android_rvh_setscheduler(p);
}
__setscheduler_uclamp(p, attr);

View File

@ -3,7 +3,7 @@
obj-y := core.o
obj-$(CONFIG_DAMON_VADDR) += ops-common.o vaddr.o
obj-$(CONFIG_DAMON_PADDR) += ops-common.o paddr.o
obj-$(CONFIG_DAMON_SYSFS) += sysfs.o
obj-$(CONFIG_DAMON_SYSFS) += sysfs-common.o sysfs-schemes.o sysfs.o
obj-$(CONFIG_DAMON_DBGFS) += dbgfs.o
obj-$(CONFIG_DAMON_RECLAIM) += reclaim.o
obj-$(CONFIG_DAMON_LRU_SORT) += lru_sort.o
obj-$(CONFIG_DAMON_RECLAIM) += modules-common.o reclaim.o
obj-$(CONFIG_DAMON_LRU_SORT) += modules-common.o lru_sort.o

View File

@ -694,6 +694,115 @@ static bool damos_valid_target(struct damon_ctx *c, struct damon_target *t,
return c->ops.get_scheme_score(c, t, r, s) >= s->quota.min_score;
}
/*
* damos_skip_charged_region() - Check if the given region or starting part of
* it is already charged for the DAMOS quota.
* @t: The target of the region.
* @rp: The pointer to the region.
* @s: The scheme to be applied.
*
* If a quota of a scheme has exceeded in a quota charge window, the scheme's
* action would applied to only a part of the target access pattern fulfilling
* regions. To avoid applying the scheme action to only already applied
* regions, DAMON skips applying the scheme action to the regions that charged
* in the previous charge window.
*
* This function checks if a given region should be skipped or not for the
* reason. If only the starting part of the region has previously charged,
* this function splits the region into two so that the second one covers the
* area that not charged in the previous charge widnow and saves the second
* region in *rp and returns false, so that the caller can apply DAMON action
* to the second one.
*
* Return: true if the region should be entirely skipped, false otherwise.
*/
static bool damos_skip_charged_region(struct damon_target *t,
struct damon_region **rp, struct damos *s)
{
struct damon_region *r = *rp;
struct damos_quota *quota = &s->quota;
unsigned long sz_to_skip;
/* Skip previously charged regions */
if (quota->charge_target_from) {
if (t != quota->charge_target_from)
return true;
if (r == damon_last_region(t)) {
quota->charge_target_from = NULL;
quota->charge_addr_from = 0;
return true;
}
if (quota->charge_addr_from &&
r->ar.end <= quota->charge_addr_from)
return true;
if (quota->charge_addr_from && r->ar.start <
quota->charge_addr_from) {
sz_to_skip = ALIGN_DOWN(quota->charge_addr_from -
r->ar.start, DAMON_MIN_REGION);
if (!sz_to_skip) {
if (damon_sz_region(r) <= DAMON_MIN_REGION)
return true;
sz_to_skip = DAMON_MIN_REGION;
}
damon_split_region_at(t, r, sz_to_skip);
r = damon_next_region(r);
*rp = r;
}
quota->charge_target_from = NULL;
quota->charge_addr_from = 0;
}
return false;
}
static void damos_update_stat(struct damos *s,
unsigned long sz_tried, unsigned long sz_applied)
{
s->stat.nr_tried++;
s->stat.sz_tried += sz_tried;
if (sz_applied)
s->stat.nr_applied++;
s->stat.sz_applied += sz_applied;
}
static void damos_apply_scheme(struct damon_ctx *c, struct damon_target *t,
struct damon_region *r, struct damos *s)
{
struct damos_quota *quota = &s->quota;
unsigned long sz = damon_sz_region(r);
struct timespec64 begin, end;
unsigned long sz_applied = 0;
int err = 0;
if (c->ops.apply_scheme) {
if (quota->esz && quota->charged_sz + sz > quota->esz) {
sz = ALIGN_DOWN(quota->esz - quota->charged_sz,
DAMON_MIN_REGION);
if (!sz)
goto update_stat;
damon_split_region_at(t, r, sz);
}
ktime_get_coarse_ts64(&begin);
if (c->callback.before_damos_apply)
err = c->callback.before_damos_apply(c, t, r, s);
if (!err)
sz_applied = c->ops.apply_scheme(c, t, r, s);
ktime_get_coarse_ts64(&end);
quota->total_charged_ns += timespec64_to_ns(&end) -
timespec64_to_ns(&begin);
quota->charged_sz += sz;
if (quota->esz && quota->charged_sz >= quota->esz) {
quota->charge_target_from = t;
quota->charge_addr_from = r->ar.end + 1;
}
}
if (s->action != DAMOS_STAT)
r->age = 0;
update_stat:
damos_update_stat(s, sz, sz_applied);
}
static void damon_do_apply_schemes(struct damon_ctx *c,
struct damon_target *t,
struct damon_region *r)
@ -702,9 +811,6 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
damon_for_each_scheme(s, c) {
struct damos_quota *quota = &s->quota;
unsigned long sz = damon_sz_region(r);
struct timespec64 begin, end;
unsigned long sz_applied = 0;
if (!s->wmarks.activated)
continue;
@ -713,70 +819,13 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
if (quota->esz && quota->charged_sz >= quota->esz)
continue;
/* Skip previously charged regions */
if (quota->charge_target_from) {
if (t != quota->charge_target_from)
continue;
if (r == damon_last_region(t)) {
quota->charge_target_from = NULL;
quota->charge_addr_from = 0;
continue;
}
if (quota->charge_addr_from &&
r->ar.end <= quota->charge_addr_from)
continue;
if (quota->charge_addr_from && r->ar.start <
quota->charge_addr_from) {
sz = ALIGN_DOWN(quota->charge_addr_from -
r->ar.start, DAMON_MIN_REGION);
if (!sz) {
if (damon_sz_region(r) <=
DAMON_MIN_REGION)
continue;
sz = DAMON_MIN_REGION;
}
damon_split_region_at(t, r, sz);
r = damon_next_region(r);
sz = damon_sz_region(r);
}
quota->charge_target_from = NULL;
quota->charge_addr_from = 0;
}
if (damos_skip_charged_region(t, &r, s))
continue;
if (!damos_valid_target(c, t, r, s))
continue;
/* Apply the scheme */
if (c->ops.apply_scheme) {
if (quota->esz &&
quota->charged_sz + sz > quota->esz) {
sz = ALIGN_DOWN(quota->esz - quota->charged_sz,
DAMON_MIN_REGION);
if (!sz)
goto update_stat;
damon_split_region_at(t, r, sz);
}
ktime_get_coarse_ts64(&begin);
sz_applied = c->ops.apply_scheme(c, t, r, s);
ktime_get_coarse_ts64(&end);
quota->total_charged_ns += timespec64_to_ns(&end) -
timespec64_to_ns(&begin);
quota->charged_sz += sz;
if (quota->esz && quota->charged_sz >= quota->esz) {
quota->charge_target_from = t;
quota->charge_addr_from = r->ar.end + 1;
}
}
if (s->action != DAMOS_STAT)
r->age = 0;
update_stat:
s->stat.nr_tried++;
s->stat.sz_tried += sz;
if (sz_applied)
s->stat.nr_applied++;
s->stat.sz_applied += sz_applied;
damos_apply_scheme(c, t, r, s);
}
}
@ -803,6 +852,53 @@ static void damos_set_effective_quota(struct damos_quota *quota)
quota->esz = esz;
}
static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
{
struct damos_quota *quota = &s->quota;
struct damon_target *t;
struct damon_region *r;
unsigned long cumulated_sz;
unsigned int score, max_score = 0;
if (!quota->ms && !quota->sz)
return;
/* New charge window starts */
if (time_after_eq(jiffies, quota->charged_from +
msecs_to_jiffies(quota->reset_interval))) {
if (quota->esz && quota->charged_sz >= quota->esz)
s->stat.qt_exceeds++;
quota->total_charged_sz += quota->charged_sz;
quota->charged_from = jiffies;
quota->charged_sz = 0;
damos_set_effective_quota(quota);
}
if (!c->ops.get_scheme_score)
return;
/* Fill up the score histogram */
memset(quota->histogram, 0, sizeof(quota->histogram));
damon_for_each_target(t, c) {
damon_for_each_region(r, t) {
if (!__damos_valid_target(r, s))
continue;
score = c->ops.get_scheme_score(c, t, r, s);
quota->histogram[score] += damon_sz_region(r);
if (score > max_score)
max_score = score;
}
}
/* Set the min score limit */
for (cumulated_sz = 0, score = max_score; ; score--) {
cumulated_sz += quota->histogram[score];
if (cumulated_sz >= quota->esz || !score)
break;
}
quota->min_score = score;
}
static void kdamond_apply_schemes(struct damon_ctx *c)
{
struct damon_target *t;
@ -810,52 +906,10 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
struct damos *s;
damon_for_each_scheme(s, c) {
struct damos_quota *quota = &s->quota;
unsigned long cumulated_sz;
unsigned int score, max_score = 0;
if (!s->wmarks.activated)
continue;
if (!quota->ms && !quota->sz)
continue;
/* New charge window starts */
if (time_after_eq(jiffies, quota->charged_from +
msecs_to_jiffies(
quota->reset_interval))) {
if (quota->esz && quota->charged_sz >= quota->esz)
s->stat.qt_exceeds++;
quota->total_charged_sz += quota->charged_sz;
quota->charged_from = jiffies;
quota->charged_sz = 0;
damos_set_effective_quota(quota);
}
if (!c->ops.get_scheme_score)
continue;
/* Fill up the score histogram */
memset(quota->histogram, 0, sizeof(quota->histogram));
damon_for_each_target(t, c) {
damon_for_each_region(r, t) {
if (!__damos_valid_target(r, s))
continue;
score = c->ops.get_scheme_score(
c, t, r, s);
quota->histogram[score] += damon_sz_region(r);
if (score > max_score)
max_score = score;
}
}
/* Set the min score limit */
for (cumulated_sz = 0, score = max_score; ; score--) {
cumulated_sz += quota->histogram[score];
if (cumulated_sz >= quota->esz || !score)
break;
}
quota->min_score = score;
damos_adjust_quota(c, s);
}
damon_for_each_target(t, c) {
@ -1176,7 +1230,8 @@ static int kdamond_fn(void *data)
if (ctx->callback.after_aggregation &&
ctx->callback.after_aggregation(ctx))
break;
kdamond_apply_schemes(ctx);
if (!list_empty(&ctx->schemes))
kdamond_apply_schemes(ctx);
kdamond_reset_aggregated(ctx);
kdamond_split_regions(ctx);
if (ctx->ops.reset_aggregated)

View File

@ -8,10 +8,8 @@
#define pr_fmt(fmt) "damon-lru-sort: " fmt
#include <linux/damon.h>
#include <linux/ioport.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include "modules-common.h"
@ -235,38 +233,31 @@ static int damon_lru_sort_turn(bool on)
return 0;
}
static struct delayed_work damon_lru_sort_timer;
static void damon_lru_sort_timer_fn(struct work_struct *work)
{
static bool last_enabled;
bool now_enabled;
now_enabled = enabled;
if (last_enabled != now_enabled) {
if (!damon_lru_sort_turn(now_enabled))
last_enabled = now_enabled;
else
enabled = last_enabled;
}
}
static DECLARE_DELAYED_WORK(damon_lru_sort_timer, damon_lru_sort_timer_fn);
static bool damon_lru_sort_initialized;
static int damon_lru_sort_enabled_store(const char *val,
const struct kernel_param *kp)
{
int rc = param_set_bool(val, kp);
bool is_enabled = enabled;
bool enable;
int err;
if (rc < 0)
return rc;
err = kstrtobool(val, &enable);
if (err)
return err;
if (!damon_lru_sort_initialized)
return rc;
if (is_enabled == enable)
return 0;
schedule_delayed_work(&damon_lru_sort_timer, 0);
/* Called before init function. The function will handle this. */
if (!ctx)
goto set_param_out;
return 0;
err = damon_lru_sort_turn(enable);
if (err)
return err;
set_param_out:
enabled = enable;
return err;
}
static const struct kernel_param_ops enabled_param_ops = {
@ -312,29 +303,19 @@ static int damon_lru_sort_after_wmarks_check(struct damon_ctx *c)
static int __init damon_lru_sort_init(void)
{
ctx = damon_new_ctx();
if (!ctx)
return -ENOMEM;
int err = damon_modules_new_paddr_ctx_target(&ctx, &target);
if (damon_select_ops(ctx, DAMON_OPS_PADDR)) {
damon_destroy_ctx(ctx);
return -EINVAL;
}
if (err)
return err;
ctx->callback.after_wmarks_check = damon_lru_sort_after_wmarks_check;
ctx->callback.after_aggregation = damon_lru_sort_after_aggregation;
target = damon_new_target();
if (!target) {
damon_destroy_ctx(ctx);
return -ENOMEM;
}
damon_add_target(ctx, target);
/* 'enabled' has set before this function, probably via command line */
if (enabled)
err = damon_lru_sort_turn(true);
schedule_delayed_work(&damon_lru_sort_timer, 0);
damon_lru_sort_initialized = true;
return 0;
return err;
}
module_init(damon_lru_sort_init);

42
mm/damon/modules-common.c Normal file
View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Common Primitives for DAMON Modules
*
* Author: SeongJae Park <sjpark@amazon.de>
*/
#include <linux/damon.h>
#include "modules-common.h"
/*
* Allocate, set, and return a DAMON context for the physical address space.
* @ctxp: Pointer to save the point to the newly created context
* @targetp: Pointer to save the point to the newly created target
*/
int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
struct damon_target **targetp)
{
struct damon_ctx *ctx;
struct damon_target *target;
ctx = damon_new_ctx();
if (!ctx)
return -ENOMEM;
if (damon_select_ops(ctx, DAMON_OPS_PADDR)) {
damon_destroy_ctx(ctx);
return -EINVAL;
}
target = damon_new_target();
if (!target) {
damon_destroy_ctx(ctx);
return -ENOMEM;
}
damon_add_target(ctx, target);
*ctxp = ctx;
*targetp = target;
return 0;
}

View File

@ -44,3 +44,6 @@
0400); \
module_param_named(nr_##qt_exceed_name, stat.qt_exceeds, ulong, \
0400);
int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
struct damon_target **targetp);

View File

@ -35,21 +35,12 @@ struct page *damon_get_page(unsigned long pfn)
void damon_ptep_mkold(pte_t *pte, struct vm_area_struct *vma, unsigned long addr)
{
bool referenced = false;
struct page *page = damon_get_page(pte_pfn(*pte));
if (!page)
return;
if (ptep_test_and_clear_young(vma, addr, pte))
referenced = true;
#ifdef CONFIG_MMU_NOTIFIER
if (mmu_notifier_clear_young(vma->vm_mm, addr, addr + PAGE_SIZE))
referenced = true;
#endif /* CONFIG_MMU_NOTIFIER */
if (referenced)
if (ptep_clear_young_notify(vma, addr, pte))
set_page_young(page);
set_page_idle(page);
@ -59,21 +50,12 @@ void damon_ptep_mkold(pte_t *pte, struct vm_area_struct *vma, unsigned long addr
void damon_pmdp_mkold(pmd_t *pmd, struct vm_area_struct *vma, unsigned long addr)
{
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
bool referenced = false;
struct page *page = damon_get_page(pmd_pfn(*pmd));
if (!page)
return;
if (pmdp_test_and_clear_young(vma, addr, pmd))
referenced = true;
#ifdef CONFIG_MMU_NOTIFIER
if (mmu_notifier_clear_young(vma->vm_mm, addr, addr + HPAGE_PMD_SIZE))
referenced = true;
#endif /* CONFIG_MMU_NOTIFIER */
if (referenced)
if (pmdp_clear_young_notify(vma, addr, pmd))
set_page_young(page);
set_page_idle(page);

View File

@ -8,10 +8,8 @@
#define pr_fmt(fmt) "damon-reclaim: " fmt
#include <linux/damon.h>
#include <linux/ioport.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include "modules-common.h"
@ -183,38 +181,31 @@ static int damon_reclaim_turn(bool on)
return 0;
}
static struct delayed_work damon_reclaim_timer;
static void damon_reclaim_timer_fn(struct work_struct *work)
{
static bool last_enabled;
bool now_enabled;
now_enabled = enabled;
if (last_enabled != now_enabled) {
if (!damon_reclaim_turn(now_enabled))
last_enabled = now_enabled;
else
enabled = last_enabled;
}
}
static DECLARE_DELAYED_WORK(damon_reclaim_timer, damon_reclaim_timer_fn);
static bool damon_reclaim_initialized;
static int damon_reclaim_enabled_store(const char *val,
const struct kernel_param *kp)
{
int rc = param_set_bool(val, kp);
bool is_enabled = enabled;
bool enable;
int err;
if (rc < 0)
return rc;
err = kstrtobool(val, &enable);
if (err)
return err;
/* system_wq might not initialized yet */
if (!damon_reclaim_initialized)
return rc;
if (is_enabled == enable)
return 0;
schedule_delayed_work(&damon_reclaim_timer, 0);
return 0;
/* Called before init function. The function will handle this. */
if (!ctx)
goto set_param_out;
err = damon_reclaim_turn(enable);
if (err)
return err;
set_param_out:
enabled = enable;
return err;
}
static const struct kernel_param_ops enabled_param_ops = {
@ -256,29 +247,19 @@ static int damon_reclaim_after_wmarks_check(struct damon_ctx *c)
static int __init damon_reclaim_init(void)
{
ctx = damon_new_ctx();
if (!ctx)
return -ENOMEM;
int err = damon_modules_new_paddr_ctx_target(&ctx, &target);
if (damon_select_ops(ctx, DAMON_OPS_PADDR)) {
damon_destroy_ctx(ctx);
return -EINVAL;
}
if (err)
return err;
ctx->callback.after_wmarks_check = damon_reclaim_after_wmarks_check;
ctx->callback.after_aggregation = damon_reclaim_after_aggregation;
target = damon_new_target();
if (!target) {
damon_destroy_ctx(ctx);
return -ENOMEM;
}
damon_add_target(ctx, target);
/* 'enabled' has set before this function, probably via command line */
if (enabled)
err = damon_reclaim_turn(true);
schedule_delayed_work(&damon_reclaim_timer, 0);
damon_reclaim_initialized = true;
return 0;
return err;
}
module_init(damon_reclaim_init);

107
mm/damon/sysfs-common.c Normal file
View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Common Primitives for DAMON Sysfs Interface
*
* Author: SeongJae Park <sj@kernel.org>
*/
#include <linux/slab.h>
#include "sysfs-common.h"
DEFINE_MUTEX(damon_sysfs_lock);
/*
* unsigned long range directory
*/
struct damon_sysfs_ul_range *damon_sysfs_ul_range_alloc(
unsigned long min,
unsigned long max)
{
struct damon_sysfs_ul_range *range = kmalloc(sizeof(*range),
GFP_KERNEL);
if (!range)
return NULL;
range->kobj = (struct kobject){};
range->min = min;
range->max = max;
return range;
}
static ssize_t min_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
struct damon_sysfs_ul_range *range = container_of(kobj,
struct damon_sysfs_ul_range, kobj);
return sysfs_emit(buf, "%lu\n", range->min);
}
static ssize_t min_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct damon_sysfs_ul_range *range = container_of(kobj,
struct damon_sysfs_ul_range, kobj);
unsigned long min;
int err;
err = kstrtoul(buf, 0, &min);
if (err)
return err;
range->min = min;
return count;
}
static ssize_t max_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
struct damon_sysfs_ul_range *range = container_of(kobj,
struct damon_sysfs_ul_range, kobj);
return sysfs_emit(buf, "%lu\n", range->max);
}
static ssize_t max_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct damon_sysfs_ul_range *range = container_of(kobj,
struct damon_sysfs_ul_range, kobj);
unsigned long max;
int err;
err = kstrtoul(buf, 0, &max);
if (err)
return err;
range->max = max;
return count;
}
void damon_sysfs_ul_range_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_ul_range, kobj));
}
static struct kobj_attribute damon_sysfs_ul_range_min_attr =
__ATTR_RW_MODE(min, 0600);
static struct kobj_attribute damon_sysfs_ul_range_max_attr =
__ATTR_RW_MODE(max, 0600);
static struct attribute *damon_sysfs_ul_range_attrs[] = {
&damon_sysfs_ul_range_min_attr.attr,
&damon_sysfs_ul_range_max_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_ul_range);
struct kobj_type damon_sysfs_ul_range_ktype = {
.release = damon_sysfs_ul_range_release,
.sysfs_ops = &kobj_sysfs_ops,
.default_groups = damon_sysfs_ul_range_groups,
};

58
mm/damon/sysfs-common.h Normal file
View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Common Primitives for DAMON Sysfs Interface
*
* Author: SeongJae Park <sj@kernel.org>
*/
#include <linux/damon.h>
#include <linux/kobject.h>
extern struct mutex damon_sysfs_lock;
struct damon_sysfs_ul_range {
struct kobject kobj;
unsigned long min;
unsigned long max;
};
struct damon_sysfs_ul_range *damon_sysfs_ul_range_alloc(
unsigned long min,
unsigned long max);
void damon_sysfs_ul_range_release(struct kobject *kobj);
extern struct kobj_type damon_sysfs_ul_range_ktype;
/*
* schemes directory
*/
struct damon_sysfs_schemes {
struct kobject kobj;
struct damon_sysfs_scheme **schemes_arr;
int nr;
};
struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void);
void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes);
extern struct kobj_type damon_sysfs_schemes_ktype;
int damon_sysfs_set_schemes(struct damon_ctx *ctx,
struct damon_sysfs_schemes *sysfs_schemes);
void damon_sysfs_schemes_update_stats(
struct damon_sysfs_schemes *sysfs_schemes,
struct damon_ctx *ctx);
int damon_sysfs_schemes_update_regions_start(
struct damon_sysfs_schemes *sysfs_schemes,
struct damon_ctx *ctx, bool total_bytes_only);
bool damos_sysfs_regions_upd_done(void);
int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx);
int damon_sysfs_schemes_clear_regions(
struct damon_sysfs_schemes *sysfs_schemes,
struct damon_ctx *ctx);

1458
mm/damon/sysfs-schemes.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -74,6 +74,8 @@ my $git_command ='export LANGUAGE=en_US.UTF-8; git';
my $tabsize = 8;
my ${CONFIG_} = "CONFIG_";
my %maybe_linker_symbol; # for externs in c exceptions, when seen in *vmlinux.lds.h
sub help {
my ($exitcode) = @_;
@ -620,6 +622,22 @@ our $signature_tags = qr{(?xi:
Cc:
)};
our @link_tags = qw(Link Closes);
#Create a search and print patterns for all these strings to be used directly below
our $link_tags_search = "";
our $link_tags_print = "";
foreach my $entry (@link_tags) {
if ($link_tags_search ne "") {
$link_tags_search .= '|';
$link_tags_print .= ' or ';
}
$entry .= ':';
$link_tags_search .= $entry;
$link_tags_print .= "'$entry'";
}
$link_tags_search = "(?:${link_tags_search})";
our $tracing_logging_tags = qr{(?xi:
[=-]*> |
<[=-]* |
@ -702,6 +720,17 @@ sub find_standard_signature {
return "";
}
our $obsolete_archives = qr{(?xi:
\Qfreedesktop.org/archives/dri-devel\E |
\Qlists.infradead.org\E |
\Qlkml.org\E |
\Qmail-archive.com\E |
\Qmailman.alsa-project.org/pipermail\E |
\Qmarc.info\E |
\Qozlabs.org/pipermail\E |
\Qspinics.net\E
)};
our @typeListMisordered = (
qr{char\s+(?:un)?signed},
qr{int\s+(?:(?:un)?signed\s+)?short\s},
@ -812,7 +841,9 @@ our %deprecated_apis = (
"get_state_synchronize_sched" => "get_state_synchronize_rcu",
"cond_synchronize_sched" => "cond_synchronize_rcu",
"kmap" => "kmap_local_page",
"kunmap" => "kunmap_local",
"kmap_atomic" => "kmap_local_page",
"kunmap_atomic" => "kunmap_local",
);
#Create a search pattern for all these strings to speed up a loop below
@ -3131,21 +3162,33 @@ sub process {
if ($sign_off =~ /^co-developed-by:$/i) {
if ($email eq $author) {
WARN("BAD_SIGN_OFF",
"Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $rawline);
"Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . $herecurr);
}
if (!defined $lines[$linenr]) {
WARN("BAD_SIGN_OFF",
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline);
} elsif ($rawlines[$linenr] !~ /^\s*signed-off-by:\s*(.*)/i) {
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . $herecurr);
} elsif ($rawlines[$linenr] !~ /^signed-off-by:\s*(.*)/i) {
WARN("BAD_SIGN_OFF",
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . $herecurr . $rawlines[$linenr] . "\n");
} elsif ($1 ne $email) {
WARN("BAD_SIGN_OFF",
"Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
"Co-developed-by and Signed-off-by: name/email do not match\n" . $herecurr . $rawlines[$linenr] . "\n");
}
}
# check if Reported-by: is followed by a Closes: tag
if ($sign_off =~ /^reported(?:|-and-tested)-by:$/i) {
if (!defined $lines[$linenr]) {
WARN("BAD_REPORTED_BY_LINK",
"Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . "\n");
} elsif ($rawlines[$linenr] !~ /^closes:\s*/i) {
WARN("BAD_REPORTED_BY_LINK",
"Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . $rawlines[$linenr] . "\n");
}
}
}
# Check Fixes: styles is correct
if (!$in_header_lines &&
$line =~ /^\s*fixes:?\s*(?:commit\s*)?[0-9a-f]{5,}\b/i) {
@ -3225,11 +3268,11 @@ sub process {
# file delta changes
$line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ ||
# filename then :
$line =~ /^\s*(?:Fixes:|Link:|$signature_tags)/i ||
# A Fixes: or Link: line or signature tag line
$line =~ /^\s*(?:Fixes:|$link_tags_search|$signature_tags)/i ||
# A Fixes:, link or signature tag line
$commit_log_possible_stack_dump)) {
WARN("COMMIT_LOG_LONG_LINE",
"Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr);
"Prefer a maximum 75 chars per line (possible unwrapped commit description?)\n" . $herecurr);
$commit_log_long_line = 1;
}
@ -3239,6 +3282,29 @@ sub process {
$commit_log_possible_stack_dump = 0;
}
# Check for odd tags before a URI/URL
if ($in_commit_log &&
$line =~ /^\s*(\w+:)\s*http/ && $1 !~ /^$link_tags_search$/) {
if ($1 =~ /^v(?:ersion)?\d+/i) {
WARN("COMMIT_LOG_VERSIONING",
"Patch version information should be after the --- line\n" . $herecurr);
} else {
WARN("COMMIT_LOG_USE_LINK",
"Unknown link reference '$1', use $link_tags_print instead\n" . $herecurr);
}
}
# Check for misuse of the link tags
if ($in_commit_log &&
$line =~ /^\s*(\w+:)\s*(\S+)/) {
my $tag = $1;
my $value = $2;
if ($tag =~ /^$link_tags_search$/ && $value !~ m{^https?://}) {
WARN("COMMIT_LOG_WRONG_LINK",
"'$tag' should be followed by a public http(s) link\n" . $herecurr);
}
}
# Check for lines starting with a #
if ($in_commit_log && $line =~ /^#/) {
if (WARN("COMMIT_COMMENT_SYMBOL",
@ -3324,6 +3390,12 @@ sub process {
$last_git_commit_id_linenr = $linenr if ($line =~ /\bcommit\s*$/i);
}
# Check for mailing list archives other than lore.kernel.org
if ($rawline =~ m{http.*\b$obsolete_archives}) {
WARN("PREFER_LORE_ARCHIVE",
"Use lore.kernel.org archive links when possible - see https://lore.kernel.org/lists.html\n" . $herecurr);
}
# Check for added, moved or deleted files
if (!$reported_maintainer_file && !$in_commit_log &&
($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ ||
@ -3693,7 +3765,7 @@ sub process {
"'$spdx_license' is not supported in LICENSES/...\n" . $herecurr);
}
if ($realfile =~ m@^Documentation/devicetree/bindings/@ &&
not $spdx_license =~ /GPL-2\.0.*BSD-2-Clause/) {
$spdx_license !~ /GPL-2\.0(?:-only)? OR BSD-2-Clause/) {
my $msg_level = \&WARN;
$msg_level = \&CHK if ($file);
if (&{$msg_level}("SPDX_LICENSE_TAG",
@ -3703,12 +3775,17 @@ sub process {
$fixed[$fixlinenr] =~ s/SPDX-License-Identifier: .*/SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)/;
}
}
if ($realfile =~ m@^include/dt-bindings/@ &&
$spdx_license !~ /GPL-2\.0(?:-only)? OR \S+/) {
WARN("SPDX_LICENSE_TAG",
"DT binding headers should be licensed (GPL-2.0-only OR .*)\n" . $herecurr);
}
}
}
}
# check for embedded filenames
if ($rawline =~ /^\+.*\Q$realfile\E/) {
if ($rawline =~ /^\+.*\b\Q$realfile\E\b/) {
WARN("EMBEDDED_FILENAME",
"It's generally not useful to have the filename in the file\n" . $herecurr);
}
@ -4971,7 +5048,7 @@ sub process {
if|for|while|switch|return|case|
volatile|__volatile__|
__attribute__|format|__extension__|
asm|__asm__)$/x)
asm|__asm__|scoped_guard)$/x)
{
# cpp #define statements have non-optional spaces, ie
# if there is a space between the name and the open
@ -5766,6 +5843,8 @@ sub process {
$var !~ /^(?:[A-Z]+_){1,5}[A-Z]{1,3}[a-z]/ &&
#Ignore Page<foo> variants
$var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
#Ignore ETHTOOL_LINK_MODE_<foo> variants
$var !~ /^ETHTOOL_LINK_MODE_/ &&
#Ignore SI style variants like nS, mV and dB
#(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE)
$var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ &&
@ -5901,6 +5980,7 @@ sub process {
$dstat !~ /$exceptions/ &&
$dstat !~ /^\.$Ident\s*=/ && # .foo =
$dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo
$dstat !~ /^case\b/ && # case ...
$dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
$dstat !~ /^while\s*$Constant\s*$Constant\s*$/ && # while (...) {...}
$dstat !~ /^for\s*$Constant$/ && # for (...)
@ -5973,6 +6053,9 @@ sub process {
# check for line continuations outside of #defines, preprocessor #, and asm
} elsif ($realfile =~ m@/vmlinux.lds.h$@) {
$line =~ s/(\w+)/$maybe_linker_symbol{$1}++/ge;
#print "REAL: $realfile\nln: $line\nkeys:", sort keys %maybe_linker_symbol;
} else {
if ($prevline !~ /^..*\\$/ &&
$line !~ /^\+\s*\#.*\\$/ && # preprocessor
@ -6910,10 +6993,22 @@ sub process {
# }
# }
# strcpy uses that should likely be strscpy
if ($line =~ /\bstrcpy\s*\(/) {
WARN("STRCPY",
"Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr);
}
# strlcpy uses that should likely be strscpy
if ($line =~ /\bstrlcpy\s*\(/) {
WARN("STRLCPY",
"Prefer strscpy over strlcpy - see: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw\@mail.gmail.com/\n" . $herecurr);
"Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr);
}
# strncpy uses that should likely be strscpy or strscpy_pad
if ($line =~ /\bstrncpy\s*\(/) {
WARN("STRNCPY",
"Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr);
}
# typecasts on min/max could be min_t/max_t
@ -7020,6 +7115,21 @@ sub process {
"arguments for function declarations should follow identifier\n" . $herecurr);
}
} elsif ($realfile =~ /\.c$/ && defined $stat &&
$stat =~ /^\+extern struct\s+(\w+)\s+(\w+)\[\];/)
{
my ($st_type, $st_name) = ($1, $2);
for my $s (keys %maybe_linker_symbol) {
#print "Linker symbol? $st_name : $s\n";
goto LIKELY_LINKER_SYMBOL
if $st_name =~ /$s/;
}
WARN("AVOID_EXTERNS",
"found a file-scoped extern type:$st_type name:$st_name in .c file\n"
. "is this a linker symbol ?\n" . $herecurr);
LIKELY_LINKER_SYMBOL:
} elsif ($realfile =~ /\.c$/ && defined $stat &&
$stat =~ /^.\s*extern\s+/)
{
@ -7128,7 +7238,7 @@ sub process {
}
# check for alloc argument mismatch
if ($line =~ /\b((?:devm_)?(?:kcalloc|kmalloc_array))\s*\(\s*sizeof\b/) {
if ($line =~ /\b((?:devm_)?((?:k|kv)?(calloc|malloc_array)(?:_node)?))\s*\(\s*sizeof\b/) {
WARN("ALLOC_ARRAY_ARGS",
"$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
}
@ -7331,6 +7441,16 @@ sub process {
}
}
# check for array definition/declarations that should use flexible arrays instead
if ($sline =~ /^[\+ ]\s*\}(?:\s*__packed)?\s*;\s*$/ &&
$prevline =~ /^\+\s*(?:\}(?:\s*__packed\s*)?|$Type)\s*$Ident\s*\[\s*(0|1)\s*\]\s*;\s*$/) {
if (ERROR("FLEXIBLE_ARRAY",
"Use C99 flexible arrays - see https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays\n" . $hereprev) &&
$1 == '0' && $fix) {
$fixed[$fixlinenr - 1] =~ s/\[\s*0\s*\]/[]/;
}
}
# nested likely/unlikely calls
if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) {
WARN("LIKELY_MISUSE",
@ -7348,6 +7468,30 @@ sub process {
}
}
# Complain about RCU Tasks Trace used outside of BPF (and of course, RCU).
our $rcu_trace_funcs = qr{(?x:
rcu_read_lock_trace |
rcu_read_lock_trace_held |
rcu_read_unlock_trace |
call_rcu_tasks_trace |
synchronize_rcu_tasks_trace |
rcu_barrier_tasks_trace |
rcu_request_urgent_qs_task
)};
our $rcu_trace_paths = qr{(?x:
kernel/bpf/ |
include/linux/bpf |
net/bpf/ |
kernel/rcu/ |
include/linux/rcu
)};
if ($line =~ /\b($rcu_trace_funcs)\s*\(/) {
if ($realfile !~ m{^$rcu_trace_paths}) {
WARN("RCU_TASKS_TRACE",
"use of RCU tasks trace is incorrect outside BPF or core RCU code\n" . $herecurr);
}
}
# check for lockdep_set_novalidate_class
if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
$line =~ /__lockdep_no_validate__\s*\)/ ) {