xref: /linux/mm/vma_init.c (revision 00c010e130e58301db2ea0cec1eadc931e1cb8cf)
13e43e260SLorenzo Stoakes // SPDX-License-Identifier: GPL-2.0-or-later
23e43e260SLorenzo Stoakes 
33e43e260SLorenzo Stoakes /*
43e43e260SLorenzo Stoakes  * Functions for initialisaing, allocating, freeing and duplicating VMAs. Shared
53e43e260SLorenzo Stoakes  * between CONFIG_MMU and non-CONFIG_MMU kernel configurations.
63e43e260SLorenzo Stoakes  */
73e43e260SLorenzo Stoakes 
83e43e260SLorenzo Stoakes #include "vma_internal.h"
93e43e260SLorenzo Stoakes #include "vma.h"
103e43e260SLorenzo Stoakes 
113e43e260SLorenzo Stoakes /* SLAB cache for vm_area_struct structures */
123e43e260SLorenzo Stoakes static struct kmem_cache *vm_area_cachep;
133e43e260SLorenzo Stoakes 
vma_state_init(void)143e43e260SLorenzo Stoakes void __init vma_state_init(void)
153e43e260SLorenzo Stoakes {
163e43e260SLorenzo Stoakes 	struct kmem_cache_args args = {
173e43e260SLorenzo Stoakes 		.use_freeptr_offset = true,
183e43e260SLorenzo Stoakes 		.freeptr_offset = offsetof(struct vm_area_struct, vm_freeptr),
193e43e260SLorenzo Stoakes 	};
203e43e260SLorenzo Stoakes 
213e43e260SLorenzo Stoakes 	vm_area_cachep = kmem_cache_create("vm_area_struct",
223e43e260SLorenzo Stoakes 			sizeof(struct vm_area_struct), &args,
233e43e260SLorenzo Stoakes 			SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_TYPESAFE_BY_RCU|
243e43e260SLorenzo Stoakes 			SLAB_ACCOUNT);
253e43e260SLorenzo Stoakes }
263e43e260SLorenzo Stoakes 
vm_area_alloc(struct mm_struct * mm)273e43e260SLorenzo Stoakes struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
283e43e260SLorenzo Stoakes {
293e43e260SLorenzo Stoakes 	struct vm_area_struct *vma;
303e43e260SLorenzo Stoakes 
313e43e260SLorenzo Stoakes 	vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
323e43e260SLorenzo Stoakes 	if (!vma)
333e43e260SLorenzo Stoakes 		return NULL;
343e43e260SLorenzo Stoakes 
353e43e260SLorenzo Stoakes 	vma_init(vma, mm);
363e43e260SLorenzo Stoakes 
373e43e260SLorenzo Stoakes 	return vma;
383e43e260SLorenzo Stoakes }
393e43e260SLorenzo Stoakes 
vm_area_init_from(const struct vm_area_struct * src,struct vm_area_struct * dest)403e43e260SLorenzo Stoakes static void vm_area_init_from(const struct vm_area_struct *src,
413e43e260SLorenzo Stoakes 			      struct vm_area_struct *dest)
423e43e260SLorenzo Stoakes {
433e43e260SLorenzo Stoakes 	dest->vm_mm = src->vm_mm;
443e43e260SLorenzo Stoakes 	dest->vm_ops = src->vm_ops;
453e43e260SLorenzo Stoakes 	dest->vm_start = src->vm_start;
463e43e260SLorenzo Stoakes 	dest->vm_end = src->vm_end;
473e43e260SLorenzo Stoakes 	dest->anon_vma = src->anon_vma;
483e43e260SLorenzo Stoakes 	dest->vm_pgoff = src->vm_pgoff;
493e43e260SLorenzo Stoakes 	dest->vm_file = src->vm_file;
503e43e260SLorenzo Stoakes 	dest->vm_private_data = src->vm_private_data;
513e43e260SLorenzo Stoakes 	vm_flags_init(dest, src->vm_flags);
523e43e260SLorenzo Stoakes 	memcpy(&dest->vm_page_prot, &src->vm_page_prot,
533e43e260SLorenzo Stoakes 	       sizeof(dest->vm_page_prot));
543e43e260SLorenzo Stoakes 	/*
553e43e260SLorenzo Stoakes 	 * src->shared.rb may be modified concurrently when called from
563e43e260SLorenzo Stoakes 	 * dup_mmap(), but the clone will reinitialize it.
573e43e260SLorenzo Stoakes 	 */
583e43e260SLorenzo Stoakes 	data_race(memcpy(&dest->shared, &src->shared, sizeof(dest->shared)));
593e43e260SLorenzo Stoakes 	memcpy(&dest->vm_userfaultfd_ctx, &src->vm_userfaultfd_ctx,
603e43e260SLorenzo Stoakes 	       sizeof(dest->vm_userfaultfd_ctx));
613e43e260SLorenzo Stoakes #ifdef CONFIG_ANON_VMA_NAME
623e43e260SLorenzo Stoakes 	dest->anon_name = src->anon_name;
633e43e260SLorenzo Stoakes #endif
643e43e260SLorenzo Stoakes #ifdef CONFIG_SWAP
653e43e260SLorenzo Stoakes 	memcpy(&dest->swap_readahead_info, &src->swap_readahead_info,
663e43e260SLorenzo Stoakes 	       sizeof(dest->swap_readahead_info));
673e43e260SLorenzo Stoakes #endif
683e43e260SLorenzo Stoakes #ifndef CONFIG_MMU
693e43e260SLorenzo Stoakes 	dest->vm_region = src->vm_region;
703e43e260SLorenzo Stoakes #endif
713e43e260SLorenzo Stoakes #ifdef CONFIG_NUMA
723e43e260SLorenzo Stoakes 	dest->vm_policy = src->vm_policy;
733e43e260SLorenzo Stoakes #endif
74*f8e97613SDavid Hildenbrand #ifdef __HAVE_PFNMAP_TRACKING
75*f8e97613SDavid Hildenbrand 	dest->pfnmap_track_ctx = NULL;
76*f8e97613SDavid Hildenbrand #endif
773e43e260SLorenzo Stoakes }
783e43e260SLorenzo Stoakes 
79*f8e97613SDavid Hildenbrand #ifdef __HAVE_PFNMAP_TRACKING
vma_pfnmap_track_ctx_dup(struct vm_area_struct * orig,struct vm_area_struct * new)80*f8e97613SDavid Hildenbrand static inline int vma_pfnmap_track_ctx_dup(struct vm_area_struct *orig,
81*f8e97613SDavid Hildenbrand 		struct vm_area_struct *new)
82*f8e97613SDavid Hildenbrand {
83*f8e97613SDavid Hildenbrand 	struct pfnmap_track_ctx *ctx = orig->pfnmap_track_ctx;
84*f8e97613SDavid Hildenbrand 
85*f8e97613SDavid Hildenbrand 	if (likely(!ctx))
86*f8e97613SDavid Hildenbrand 		return 0;
87*f8e97613SDavid Hildenbrand 
88*f8e97613SDavid Hildenbrand 	/*
89*f8e97613SDavid Hildenbrand 	 * We don't expect to ever hit this. If ever required, we would have
90*f8e97613SDavid Hildenbrand 	 * to duplicate the tracking.
91*f8e97613SDavid Hildenbrand 	 */
92*f8e97613SDavid Hildenbrand 	if (unlikely(kref_read(&ctx->kref) >= REFCOUNT_MAX))
93*f8e97613SDavid Hildenbrand 		return -ENOMEM;
94*f8e97613SDavid Hildenbrand 	kref_get(&ctx->kref);
95*f8e97613SDavid Hildenbrand 	new->pfnmap_track_ctx = ctx;
96*f8e97613SDavid Hildenbrand 	return 0;
97*f8e97613SDavid Hildenbrand }
98*f8e97613SDavid Hildenbrand 
vma_pfnmap_track_ctx_release(struct vm_area_struct * vma)99*f8e97613SDavid Hildenbrand static inline void vma_pfnmap_track_ctx_release(struct vm_area_struct *vma)
100*f8e97613SDavid Hildenbrand {
101*f8e97613SDavid Hildenbrand 	struct pfnmap_track_ctx *ctx = vma->pfnmap_track_ctx;
102*f8e97613SDavid Hildenbrand 
103*f8e97613SDavid Hildenbrand 	if (likely(!ctx))
104*f8e97613SDavid Hildenbrand 		return;
105*f8e97613SDavid Hildenbrand 
106*f8e97613SDavid Hildenbrand 	kref_put(&ctx->kref, pfnmap_track_ctx_release);
107*f8e97613SDavid Hildenbrand 	vma->pfnmap_track_ctx = NULL;
108*f8e97613SDavid Hildenbrand }
109*f8e97613SDavid Hildenbrand #else
vma_pfnmap_track_ctx_dup(struct vm_area_struct * orig,struct vm_area_struct * new)110*f8e97613SDavid Hildenbrand static inline int vma_pfnmap_track_ctx_dup(struct vm_area_struct *orig,
111*f8e97613SDavid Hildenbrand 		struct vm_area_struct *new)
112*f8e97613SDavid Hildenbrand {
113*f8e97613SDavid Hildenbrand 	return 0;
114*f8e97613SDavid Hildenbrand }
vma_pfnmap_track_ctx_release(struct vm_area_struct * vma)115*f8e97613SDavid Hildenbrand static inline void vma_pfnmap_track_ctx_release(struct vm_area_struct *vma)
116*f8e97613SDavid Hildenbrand {
117*f8e97613SDavid Hildenbrand }
118*f8e97613SDavid Hildenbrand #endif
119*f8e97613SDavid Hildenbrand 
vm_area_dup(struct vm_area_struct * orig)1203e43e260SLorenzo Stoakes struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
1213e43e260SLorenzo Stoakes {
1223e43e260SLorenzo Stoakes 	struct vm_area_struct *new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
1233e43e260SLorenzo Stoakes 
1243e43e260SLorenzo Stoakes 	if (!new)
1253e43e260SLorenzo Stoakes 		return NULL;
1263e43e260SLorenzo Stoakes 
1273e43e260SLorenzo Stoakes 	ASSERT_EXCLUSIVE_WRITER(orig->vm_flags);
1283e43e260SLorenzo Stoakes 	ASSERT_EXCLUSIVE_WRITER(orig->vm_file);
1293e43e260SLorenzo Stoakes 	vm_area_init_from(orig, new);
130*f8e97613SDavid Hildenbrand 
131*f8e97613SDavid Hildenbrand 	if (vma_pfnmap_track_ctx_dup(orig, new)) {
132*f8e97613SDavid Hildenbrand 		kmem_cache_free(vm_area_cachep, new);
133*f8e97613SDavid Hildenbrand 		return NULL;
134*f8e97613SDavid Hildenbrand 	}
1353e43e260SLorenzo Stoakes 	vma_lock_init(new, true);
1363e43e260SLorenzo Stoakes 	INIT_LIST_HEAD(&new->anon_vma_chain);
1373e43e260SLorenzo Stoakes 	vma_numab_state_init(new);
1383e43e260SLorenzo Stoakes 	dup_anon_vma_name(orig, new);
1393e43e260SLorenzo Stoakes 
1403e43e260SLorenzo Stoakes 	return new;
1413e43e260SLorenzo Stoakes }
1423e43e260SLorenzo Stoakes 
vm_area_free(struct vm_area_struct * vma)1433e43e260SLorenzo Stoakes void vm_area_free(struct vm_area_struct *vma)
1443e43e260SLorenzo Stoakes {
1453e43e260SLorenzo Stoakes 	/* The vma should be detached while being destroyed. */
1463e43e260SLorenzo Stoakes 	vma_assert_detached(vma);
1473e43e260SLorenzo Stoakes 	vma_numab_state_free(vma);
1483e43e260SLorenzo Stoakes 	free_anon_vma_name(vma);
149*f8e97613SDavid Hildenbrand 	vma_pfnmap_track_ctx_release(vma);
1503e43e260SLorenzo Stoakes 	kmem_cache_free(vm_area_cachep, vma);
1513e43e260SLorenzo Stoakes }
152