---
# System prepended metadata

title: Linux 核心 Copy On Write 實作機制 - Record
tags: [linux2021, Linux kernel COW]

---

# Linux 核心 Copy On Write 實作機制 - Record
contributed by < [`linD026`](https://github.com/linD026) >
###### tags: `Linux kernel COW` , `linux2021`
---
[/mm/filemap.c](https://elixir.bootlin.com/linux/v5.10.38/source/mm/filemap.c#L998)
```cpp=
/*
 * FIXME: remove all knowledge of the buffer layer from the core VM
 */
#include <linux/buffer_head.h> /* for try_to_free_buffers */

#include <asm/mman.h>

/*
 * Shared mappings implemented 30.11.1994. It's not fully working yet,
 * though.
 *
 * Shared mappings now work. 15.8.1995  Bruno.
 *
 * finished 'unifying' the page and buffer cache and SMP-threaded the
 * page-cache, 21.05.1999, Ingo Molnar <mingo@redhat.com>
 *
 * SMP-threaded pagemap-LRU 1999, Andrea Arcangeli <andrea@suse.de>
 */

/*
 * Lock ordering:
 *
 *  ->i_mmap_rwsem		(truncate_pagecache)
 *    ->private_lock		(__free_pte->__set_page_dirty_buffers)
 *      ->swap_lock		(exclusive_swap_page, others)
 *        ->i_pages lock
 *
 *  ->i_mutex
 *    ->i_mmap_rwsem		(truncate->unmap_mapping_range)
 *
 *  ->mmap_lock
 *    ->i_mmap_rwsem
 *      ->page_table_lock or pte_lock	(various, mainly in memory.c)
 *        ->i_pages lock	(arch-dependent flush_dcache_mmap_lock)
 *
 *  ->mmap_lock
 *    ->lock_page		(access_process_vm)
 *
 *  ->i_mutex			(generic_perform_write)
 *    ->mmap_lock		(fault_in_pages_readable->do_page_fault)
 *
 *  bdi->wb.list_lock
 *    sb_lock			(fs/fs-writeback.c)
 *    ->i_pages lock		(__sync_single_inode)
 *
 *  ->i_mmap_rwsem
 *    ->anon_vma.lock		(vma_adjust)
 *
 *  ->anon_vma.lock
 *    ->page_table_lock or pte_lock	(anon_vma_prepare and various)
 *
 *  ->page_table_lock or pte_lock
 *    ->swap_lock		(try_to_unmap_one)
 *    ->private_lock		(try_to_unmap_one)
 *    ->i_pages lock		(try_to_unmap_one)
 *    ->pgdat->lru_lock		(follow_page->mark_page_accessed)
 *    ->pgdat->lru_lock		(check_pte_range->isolate_lru_page)
 *    ->private_lock		(page_remove_rmap->set_page_dirty)
 *    ->i_pages lock		(page_remove_rmap->set_page_dirty)
 *    bdi.wb->list_lock		(page_remove_rmap->set_page_dirty)
 *    ->inode->i_lock		(page_remove_rmap->set_page_dirty)
 *    ->memcg->move_lock	(page_remove_rmap->lock_page_memcg)
 *    bdi.wb->list_lock		(zap_pte_range->set_page_dirty)
 *    ->inode->i_lock		(zap_pte_range->set_page_dirty)
 *    ->private_lock		(zap_pte_range->__set_page_dirty_buffers)
 *
 * ->i_mmap_rwsem
 *   ->tasklist_lock            (memory_failure, collect_procs_ao)
 */
```

---

## Lazy TLB

```shell
          <idle>-0       [001] d...  8281.860587: enter_lazy_tlb <-__schedule
           <...>-7615    [009] ....  8281.860587: get_close_on_exec <-do_fcntl
           <...>-7615    [009] ....  8281.860587: rcu_read_unlock_strict <-get_close_on_exec
           <...>-7615    [009] d...  8281.860588: exit_to_user_mode_prepare <-syscall_exit_to_user_mode
   kworker/u24:3-7503    [001] d...  8281.860588: finish_task_switch <-__schedule
```

---

## wait_on_page_bit

```shell
            bash-7535    [004] ....  8473.950727: down_write <-unmap_mapping_pages
            bash-7535    [004] ....  8473.950727: _cond_resched <-down_write
            bash-7535    [004] ....  8473.950727: rcu_all_qs <-_cond_resched
            bash-7535    [004] ....  8473.950728: up_write <-unmap_mapping_pages
            bash-7535    [004] ....  8473.950728: truncate_inode_pages_range <-truncate_pagecache
            bash-7535    [004] ....  8473.950729: pagevec_lookup_entries <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950729: find_get_entries <-pagevec_lookup_entries
            bash-7535    [004] ....  8473.950729: rcu_read_unlock_strict <-find_get_entries
            bash-7535    [004] ....  8473.950730: unlock_page <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950730: delete_from_page_cache_batch <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950730: truncate_exceptional_pvec_entries.part.0 <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950730: __pagevec_release <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950731: lru_add_drain_cpu <-__pagevec_release
            bash-7535    [004] ....  8473.950731: release_pages <-__pagevec_release
            bash-7535    [004] ....  8473.950731: mem_cgroup_uncharge_list <-release_pages
            bash-7535    [004] ....  8473.950731: free_unref_page_list <-release_pages
            bash-7535    [004] ....  8473.950732: _cond_resched <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950732: rcu_all_qs <-_cond_resched
            bash-7535    [004] ....  8473.950732: pagevec_lookup_entries <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950732: find_get_entries <-pagevec_lookup_entries
            bash-7535    [004] ....  8473.950733: rcu_read_unlock_strict <-find_get_entries
            bash-7535    [004] ....  8473.950733: _cond_resched <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950733: rcu_all_qs <-_cond_resched
            bash-7535    [004] ....  8473.950733: pagevec_lookup_entries <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950734: find_get_entries <-pagevec_lookup_entries
            bash-7535    [004] ....  8473.950734: rcu_read_unlock_strict <-find_get_entries
            bash-7535    [004] ....  8473.950734: _cond_resched <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950734: rcu_all_qs <-_cond_resched
            bash-7535    [004] ....  8473.950735: wait_on_page_writeback <-truncate_inode_pages_range
            bash-7535    [004] ....  8473.950735: page_mapping <-wait_on_page_writeback
            bash-7535    [004] ....  8473.950735: wait_on_page_bit <-wait_on_page_writeback
            bash-7535    [004] ....  8473.950735: _raw_spin_lock_irq <-wait_on_page_bit
            bash-7535    [004] ....  8473.950736: io_schedule <-wait_on_page_bit
            bash-7535    [004] ....  8473.950736: io_schedule_prepare <-io_schedule
            bash-7535    [004] ....  8473.950736: schedule <-io_schedule
            bash-7535    [004] d...  8473.950737: rcu_note_context_switch <-__schedule
            bash-7535    [004] d...  8473.950737: rcu_qs <-rcu_note_context_switch
            bash-7535    [004] d...  8473.950737: _raw_spin_lock <-__schedule
            bash-7535    [004] d...  8473.950737: update_rq_clock <-__schedule
            bash-7535    [004] d...  8473.950738: psi_task_change <-dequeue_task
            bash-7535    [004] d...  8473.950738: psi_flags_change <-psi_task_change
            bash-7535    [004] d...  8473.950738: psi_group_change <-psi_task_change
            bash-7535    [004] d...  8473.950739: record_times <-psi_group_change
            bash-7535    [004] d...  8473.950739: psi_group_change <-psi_task_change
            bash-7535    [004] d...  8473.950739: record_times <-psi_group_change
            bash-7535    [004] d...  8473.950740: psi_group_change <-psi_task_change
            bash-7535    [004] d...  8473.950740: record_times <-psi_group_change
            bash-7535    [004] d...  8473.950740: psi_group_change <-psi_task_change
            bash-7535    [004] d...  8473.950741: record_times <-psi_group_change
            bash-7535    [004] d...  8473.950741: psi_group_change <-psi_task_change
            bash-7535    [004] d...  8473.950741: record_times <-psi_group_change
            bash-7535    [004] d...  8473.950742: psi_group_change <-psi_task_change
            bash-7535    [004] d...  8473.950742: record_times <-psi_group_change
            bash-7535    [004] d...  8473.950742: psi_group_change <-psi_task_change
            bash-7535    [004] d...  8473.950743: record_times <-psi_group_change
            bash-7535    [004] d...  8473.950743: dequeue_task_fair <-dequeue_task
            bash-7535    [004] d...  8473.950743: dequeue_entity <-dequeue_task_fair
            bash-7535    [004] d...  8473.950744: update_curr <-dequeue_entity
            bash-7535    [004] d...  8473.950744: update_min_vruntime <-update_curr
            bash-7535    [004] d...  8473.950744: cpuacct_charge <-update_curr
            bash-7535    [004] d...  8473.950745: rcu_read_unlock_strict <-cpuacct_charge
            bash-7535    [004] d...  8473.950745: __cgroup_account_cputime <-update_curr
```



```shell
          <idle>-0       [004] d...  8473.954791: call_cpuidle <-do_idle
          <idle>-0       [004] d...  8473.954791: cpuidle_enter <-call_cpuidle
          <idle>-0       [004] d...  8473.954792: tick_nohz_get_next_hrtimer <-cpuidle_enter
          <idle>-0       [004] d...  8473.954792: cpuidle_enter_state <-cpuidle_enter
          <idle>-0       [004] d...  8473.954792: sched_idle_set_state <-cpuidle_enter_state
          <idle>-0       [004] d...  8473.954792: rcu_idle_enter <-cpuidle_enter_state
          <idle>-0       [004] d...  8473.954793: intel_idle <-cpuidle_enter_state
          <idle>-0       [004] dN..  8473.955181: rcu_idle_exit <-cpuidle_enter_state
          <idle>-0       [004] dN..  8473.955181: sched_idle_set_state <-cpuidle_enter_state
          <idle>-0       [004] .N..  8473.955182: cpuidle_reflect <-do_idle
          <idle>-0       [004] .N..  8473.955182: menu_reflect <-cpuidle_reflect
          <idle>-0       [004] .N..  8473.955182: tick_nohz_idle_got_tick <-menu_reflect
          <idle>-0       [004] .N..  8473.955182: arch_cpu_idle_exit <-do_idle
          <idle>-0       [004] .N..  8473.955183: tick_nohz_idle_exit <-do_idle
          <idle>-0       [004] dN..  8473.955183: ktime_get <-tick_nohz_idle_exit
          <idle>-0       [004] dN..  8473.955183: update_ts_time_stats <-tick_nohz_idle_exit
          <idle>-0       [004] dN..  8473.955183: nr_iowait_cpu <-update_ts_time_stats
          <idle>-0       [004] .N..  8473.955184: flush_smp_call_function_from_idle <-do_idle
          <idle>-0       [004] .N..  8473.955184: schedule_idle <-do_idle
          <idle>-0       [004] dN..  8473.955184: rcu_note_context_switch <-__schedule
          <idle>-0       [004] dN..  8473.955185: rcu_qs <-rcu_note_context_switch
          <idle>-0       [004] dN..  8473.955185: _raw_spin_lock <-__schedule
          <idle>-0       [004] dN..  8473.955185: update_rq_clock <-__schedule
          <idle>-0       [004] dN..  8473.955186: pick_next_task_fair <-__schedule
          <idle>-0       [004] dN..  8473.955186: put_prev_task_idle <-pick_next_task_fair
          <idle>-0       [004] dN..  8473.955187: pick_next_entity <-pick_next_task_fair
          <idle>-0       [004] dN..  8473.955187: clear_buddies <-pick_next_entity
          <idle>-0       [004] dN..  8473.955187: set_next_entity <-pick_next_task_fair
          <idle>-0       [004] dN..  8473.955188: __update_load_avg_se <-update_load_avg
          <idle>-0       [004] dN..  8473.955188: __update_load_avg_cfs_rq <-update_load_avg
          <idle>-0       [004] dN..  8473.955188: pick_next_entity <-pick_next_task_fair
          <idle>-0       [004] dN..  8473.955188: clear_buddies <-pick_next_entity
          <idle>-0       [004] dN..  8473.955189: set_next_entity <-pick_next_task_fair
          <idle>-0       [004] dN..  8473.955189: __update_load_avg_se <-update_load_avg
          <idle>-0       [004] dN..  8473.955189: __update_load_avg_cfs_rq <-update_load_avg
          <idle>-0       [004] d...  8473.955190: psi_task_switch <-__schedule
          <idle>-0       [004] d...  8473.955190: psi_flags_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955191: psi_group_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955191: record_times <-psi_group_change
          <idle>-0       [004] d...  8473.955191: psi_group_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955192: record_times <-psi_group_change
          <idle>-0       [004] d...  8473.955192: psi_group_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955192: record_times <-psi_group_change
          <idle>-0       [004] d...  8473.955193: psi_group_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955193: record_times <-psi_group_change
          <idle>-0       [004] d...  8473.955193: psi_group_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955194: record_times <-psi_group_change
          <idle>-0       [004] d...  8473.955194: psi_group_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955194: record_times <-psi_group_change
          <idle>-0       [004] d...  8473.955195: psi_group_change <-psi_task_switch
          <idle>-0       [004] d...  8473.955195: record_times <-psi_group_change
          <idle>-0       [004] d...  8473.955196: switch_mm_irqs_off <-__schedule
            bash-7535    [004] d...  8473.955197: finish_task_switch <-__schedule
            bash-7535    [004] ....  8473.955197: finish_wait <-wait_on_page_bit
```

---

## wake_up_page_bit

```shell
            bash-7535    [004] ....  8473.952905: bio_add_page <-ext4_bio_write_page
            bash-7535    [004] ....  8473.952906: __bio_try_merge_page <-bio_add_page
            bash-7535    [004] ....  8473.952906: __bio_add_page <-bio_add_page
            bash-7535    [004] ....  8473.952906: wbc_account_cgroup_owner <-ext4_bio_write_page
            bash-7535    [004] ....  8473.952906: unlock_page <-ext4_bio_write_page
            bash-7535    [004] ....  8473.952907: wake_up_page_bit <-unlock_page
            bash-7535    [004] ....  8473.952907: _raw_spin_lock_irqsave <-wake_up_page_bit
            bash-7535    [004] d...  8473.952907: __wake_up_locked_key_bookmark <-wake_up_page_bit
            bash-7535    [004] d...  8473.952908: __wake_up_common <-__wake_up_locked_key_bookmark
            bash-7535    [004] d...  8473.952908: wake_page_function <-__wake_up_common
            bash-7535    [004] d...  8473.952908: wake_up_state <-wake_page_function
            bash-7535    [004] d...  8473.952909: try_to_wake_up <-wake_up_state
            bash-7535    [004] d...  8473.952909: _raw_spin_lock_irqsave <-try_to_wake_up
            bash-7535    [004] d...  8473.952909: select_task_rq_fair <-try_to_wake_up
            bash-7535    [004] d...  8473.952910: available_idle_cpu <-select_task_rq_fair

```