On Tue, Jul 11, 2023 at 6:27 PM Hugh Dickins <hughd@xxxxxxxxxx> wrote: > > Smatch has observed that pte_offset_map_lock() is now allowed to fail, > and then ptl should not be unlocked. Use -EAGAIN here like elsewhere. > > Signed-off-by: Hugh Dickins <hughd@xxxxxxxxxx> Looks correct to me, thanks Hugh! If it's useful, feel free to take: Reviewed-by: Axel Rasmussen <axelrasmussen@xxxxxxxxxx> > --- > Axel, Peter: this seems right as a fix to the patch in mm-unstable; > but in preparing this, I noticed mfill_atomic()'s code before calling > mfill_atomic_pte(), and think that my original choice of -EFAULT was > therefore better than -EAGAIN for all of these; and that mfill_atomic()'s > BUG_ONs there would be better deleted (and is its BUG_ON(folio) safe??). > Something one of us should address, after this fixup is in akpm's tree. Agreed, dealing with the BUG_ONs is something I have been meaning to do as checkpatch bothers me about it frequently. What this code is trying to do is to enforce the contract that: if mfill_atomic_pte failed, then it must have released *folio and set it to NULL. But, you're exactly right that if we had such a bug, it would mean we leaked one page in an unusual error case - not great, but not worth crashing the kernel either. For UFFDIO_POISON this doesn't really apply because it doesn't allocate or get a reference to a page in any case. For other cases like UFFDIO_COPY where it does matter, I think it's fine as is regardless of the error code returned (as long as it's not -ENOENT :) ). mfill_atomic_pte_copy() is sure to set `*foliop = NULL` before it attempts this lock (in mfill_atomic_install_pte). So -EAGAIN or -EFAULT should work equally well at least from that perspective. I somewhat prefer -EAGAIN, but maybe I'm missing something. > > mm/userfaultfd.c | 4 ++++ > 1 file changed, 4 insertions(+) > > --- a/mm/userfaultfd.c > +++ b/mm/userfaultfd.c > @@ -300,7 +300,10 @@ static int mfill_atomic_pte_poison(pmd_t *dst_pmd, > spinlock_t *ptl; > > _dst_pte = make_pte_marker(PTE_MARKER_POISONED); > + ret = -EAGAIN; > dst_pte = pte_offset_map_lock(dst_mm, dst_pmd, dst_addr, &ptl); > + if (!dst_pte) > + goto out; > > if (mfill_file_over_size(dst_vma, dst_addr)) { > ret = -EFAULT; > @@ -319,6 +322,7 @@ static int mfill_atomic_pte_poison(pmd_t *dst_pmd, > ret = 0; > out_unlock: > pte_unmap_unlock(dst_pte, ptl); > +out: > return ret; > } >