FROMLIST: mm: rcu safe vma->vm_file freeing
Defer freeing of vma->vm_file when freeing vmas. This is to allow speculative page faults in the mapped file case. Signed-off-by: Michel Lespinasse <michel@lespinasse.org> Link: https://lore.kernel.org/all/20210407014502.24091-24-michel@lespinasse.org/ Bug: 161210518 Signed-off-by: Suren Baghdasaryan <surenb@google.com> Change-Id: Ic766bc2086db82eae9f3aadf0f23dd743be1c464
This commit is contained in:
committed by
Todd Kjos
parent
fea117c94a
commit
48e35d053f
@@ -285,6 +285,7 @@ err:
|
||||
mmap_write_unlock(mm);
|
||||
err_free:
|
||||
bprm->vma = NULL;
|
||||
VM_BUG_ON(vma->vm_file);
|
||||
vm_area_free(vma);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -381,12 +381,19 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
|
||||
return new;
|
||||
}
|
||||
|
||||
static inline void ____vm_area_free(struct vm_area_struct *vma)
|
||||
{
|
||||
if (vma->vm_file)
|
||||
fput(vma->vm_file);
|
||||
kmem_cache_free(vm_area_cachep, vma);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPECULATIVE_PAGE_FAULT
|
||||
static void __vm_area_free(struct rcu_head *head)
|
||||
{
|
||||
struct vm_area_struct *vma = container_of(head, struct vm_area_struct,
|
||||
vm_rcu);
|
||||
kmem_cache_free(vm_area_cachep, vma);
|
||||
____vm_area_free(vma);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -399,7 +406,7 @@ void vm_area_free(struct vm_area_struct *vma)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
kmem_cache_free(vm_area_cachep, vma);
|
||||
____vm_area_free(vma);
|
||||
}
|
||||
|
||||
static void account_kernel_stack(struct task_struct *tsk, int account)
|
||||
@@ -657,6 +664,7 @@ fail_uprobe_end:
|
||||
fail_nomem_anon_vma_fork:
|
||||
mpol_put(vma_policy(tmp));
|
||||
fail_nomem_policy:
|
||||
tmp->vm_file = NULL; /* prevents fput within vm_area_free() */
|
||||
vm_area_free(tmp);
|
||||
fail_nomem:
|
||||
retval = -ENOMEM;
|
||||
|
||||
11
mm/mmap.c
11
mm/mmap.c
@@ -183,9 +183,8 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
|
||||
might_sleep();
|
||||
if (vma->vm_ops && vma->vm_ops->close)
|
||||
vma->vm_ops->close(vma);
|
||||
if (vma->vm_file)
|
||||
fput(vma->vm_file);
|
||||
mpol_put(vma_policy(vma));
|
||||
/* fput(vma->vm_file) happens in vm_area_free after an RCU delay. */
|
||||
vm_area_free(vma);
|
||||
return next;
|
||||
}
|
||||
@@ -953,7 +952,8 @@ again:
|
||||
if (remove_next) {
|
||||
if (file) {
|
||||
uprobe_munmap(next, next->vm_start, next->vm_end);
|
||||
fput(file);
|
||||
/* fput(file) happens whthin vm_area_free(next) */
|
||||
VM_BUG_ON(file != next->vm_file);
|
||||
}
|
||||
if (next->anon_vma)
|
||||
anon_vma_merge(vma, next);
|
||||
@@ -1817,7 +1817,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
||||
* fput the vma->vm_file here or we would add an extra fput for file
|
||||
* and cause general protection fault ultimately.
|
||||
*/
|
||||
fput(vma->vm_file);
|
||||
/* fput happens within vm_area_free */
|
||||
vm_area_free(vma);
|
||||
vma = merge;
|
||||
/* Update vm_flags to pick up the change. */
|
||||
@@ -1889,6 +1889,7 @@ unmap_and_free_vma:
|
||||
if (vm_flags & VM_SHARED)
|
||||
mapping_unmap_writable(file->f_mapping);
|
||||
free_vma:
|
||||
VM_BUG_ON(vma->vm_file);
|
||||
vm_area_free(vma);
|
||||
unacct_error:
|
||||
if (charged)
|
||||
@@ -2761,6 +2762,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||
out_free_mpol:
|
||||
mpol_put(vma_policy(new));
|
||||
out_free_vma:
|
||||
new->vm_file = NULL; /* prevents fput within vm_area_free() */
|
||||
vm_area_free(new);
|
||||
return err;
|
||||
}
|
||||
@@ -3302,6 +3304,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
|
||||
out_free_mempol:
|
||||
mpol_put(vma_policy(new_vma));
|
||||
out_free_vma:
|
||||
new_vma->vm_file = NULL; /* Prevent fput within vm_area_free */
|
||||
vm_area_free(new_vma);
|
||||
out:
|
||||
return NULL;
|
||||
|
||||
@@ -654,9 +654,8 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma)
|
||||
{
|
||||
if (vma->vm_ops && vma->vm_ops->close)
|
||||
vma->vm_ops->close(vma);
|
||||
if (vma->vm_file)
|
||||
fput(vma->vm_file);
|
||||
put_nommu_region(vma->vm_region);
|
||||
/* fput(vma->vm_file) happens within vm_area_free() */
|
||||
vm_area_free(vma);
|
||||
}
|
||||
|
||||
@@ -1254,8 +1253,7 @@ error:
|
||||
if (region->vm_file)
|
||||
fput(region->vm_file);
|
||||
kmem_cache_free(vm_region_jar, region);
|
||||
if (vma->vm_file)
|
||||
fput(vma->vm_file);
|
||||
/* fput(vma->vm_file) happens within vm_area_free() */
|
||||
vm_area_free(vma);
|
||||
return ret;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user