diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-07 00:48:54 +0300 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-07 00:50:59 +0300 |
commit | b2edffdd912b4205899a8efa0974dfbbc3216109 (patch) | |
tree | 64f8f993ab48978b5a3a13912bba685d48b1a04e /mm/mremap.c | |
parent | 8f778bbc542ddf8f6243b21d6aca087e709cabdc (diff) | |
download | linux-b2edffdd912b4205899a8efa0974dfbbc3216109.tar.xz |
fix mremap() vs. ioctx_kill() race
teach ->mremap() method to return an error and have it fail for
aio mappings in process of being killed
Note that in case of ->mremap() failure we need to undo move_page_tables()
we'd already done; we could call ->mremap() first, but then the failure of
move_page_tables() would require undoing whatever _successful_ ->mremap()
has done, which would be a lot more headache in general.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm/mremap.c')
-rw-r--r-- | mm/mremap.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/mm/mremap.c b/mm/mremap.c index 57dadc025c64..2dc44b1cb1df 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -286,8 +286,14 @@ static unsigned long move_vma(struct vm_area_struct *vma, old_len = new_len; old_addr = new_addr; new_addr = -ENOMEM; - } else if (vma->vm_file && vma->vm_file->f_op->mremap) - vma->vm_file->f_op->mremap(vma->vm_file, new_vma); + } else if (vma->vm_file && vma->vm_file->f_op->mremap) { + err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma); + if (err < 0) { + move_page_tables(new_vma, new_addr, vma, old_addr, + moved_len, true); + return err; + } + } /* Conceal VM_ACCOUNT so old reservation is not undone */ if (vm_flags & VM_ACCOUNT) { |