mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
mm/filemap: finish fault cleanup before dropping the fault lock
On a retried fault, a fatal signal interrupting the folio lock wait
makes lock_folio_maybe_drop_mmap() drop the fault lock without pinning
the file. However, filemap_fault() may still need to release
mapping->invalidate_lock. A concurrent munmap() can release the last
file reference and free the mapping before that unlock.
Defer dropping the fault lock to filemap_fault()'s retry cleanup, after
releasing invalidate_lock. If the fault lock was already dropped for
I/O, release the existing file reference instead. Keep the fault lock
held for FAULT_FLAG_RETRY_NOWAIT as before.
Fixes: 730633f0b7 ("mm: Protect operations adding pages to page cache with invalidate_lock")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Reviewed-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-8-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
This commit is contained in:
parent
8ccb6ded6a
commit
97156a6c35
37
mm/filemap.c
37
mm/filemap.c
|
|
@ -3308,11 +3308,11 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
|
|||
* @folio - the folio to lock.
|
||||
* @fpin - the pointer to the file we may pin (or is already pinned).
|
||||
*
|
||||
* This works similar to lock_folio_or_retry in that it can drop the
|
||||
* mmap_lock. It differs in that it actually returns the folio locked
|
||||
* if it returns 1 and 0 if it couldn't lock the folio. If we did have
|
||||
* to drop the mmap_lock then fpin will point to the pinned file and
|
||||
* needs to be fput()'ed at a later point.
|
||||
* Returns 1 with the folio locked, or 0 if locking failed.
|
||||
*
|
||||
* On both entry and return, a non-NULL *fpin means the fault lock has
|
||||
* already been dropped and the caller must eventually fput() the file.
|
||||
* Otherwise the fault lock is still held, including on failure.
|
||||
*/
|
||||
static int lock_folio_maybe_drop_mmap(struct vm_fault *vmf, struct folio *folio,
|
||||
struct file **fpin)
|
||||
|
|
@ -3329,21 +3329,9 @@ static int lock_folio_maybe_drop_mmap(struct vm_fault *vmf, struct folio *folio,
|
|||
return 0;
|
||||
|
||||
*fpin = maybe_unlock_mmap_for_io(vmf, *fpin);
|
||||
if (vmf->flags & FAULT_FLAG_KILLABLE) {
|
||||
if (__folio_lock_killable(folio)) {
|
||||
/*
|
||||
* We didn't have the right flags to drop the
|
||||
* fault lock, but all fault_handlers only check
|
||||
* for fatal signals if we return VM_FAULT_RETRY,
|
||||
* so we need to drop the fault lock here and
|
||||
* return 0 if we don't have a fpin.
|
||||
*/
|
||||
if (*fpin == NULL)
|
||||
release_fault_lock(vmf);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
__folio_lock(folio);
|
||||
if (vmf->flags & FAULT_FLAG_KILLABLE)
|
||||
return !__folio_lock_killable(folio);
|
||||
__folio_lock(folio);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -3572,7 +3560,7 @@ static vm_fault_t filemap_fault_recheck_pte_none(struct vm_fault *vmf)
|
|||
* vma->vm_mm->mmap_lock must be held on entry.
|
||||
*
|
||||
* If our return value has VM_FAULT_RETRY set, it's because the mmap_lock
|
||||
* may be dropped before doing I/O or by lock_folio_maybe_drop_mmap().
|
||||
* may be dropped before doing I/O or when aborting an interrupted wait.
|
||||
*
|
||||
* If our return value does not have VM_FAULT_RETRY set, the mmap_lock
|
||||
* has not been released.
|
||||
|
|
@ -3728,9 +3716,8 @@ vm_fault_t filemap_fault(struct vm_fault *vmf)
|
|||
|
||||
out_retry:
|
||||
/*
|
||||
* We dropped the mmap_lock, we need to return to the fault handler to
|
||||
* re-find the vma and come back and find our hopefully still populated
|
||||
* page.
|
||||
* With fpin set, the fault lock was already dropped. Otherwise it is
|
||||
* still held. Release invalidate_lock before dropping either protection.
|
||||
*/
|
||||
if (!IS_ERR(folio))
|
||||
folio_put(folio);
|
||||
|
|
@ -3738,6 +3725,8 @@ vm_fault_t filemap_fault(struct vm_fault *vmf)
|
|||
filemap_invalidate_unlock_shared(mapping);
|
||||
if (fpin)
|
||||
fput(fpin);
|
||||
else if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
|
||||
release_fault_lock(vmf);
|
||||
return ret | VM_FAULT_RETRY;
|
||||
}
|
||||
EXPORT_SYMBOL(filemap_fault);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user