> Date: Thu, 1 Oct 2020 14:10:56 +0200
> From: Martin Pieuchot <[email protected]>
>
> While studying a bug report from naddy@ in 2017 when testing guenther@'s
> amap/anon locking diff I figured out that we have been too optimistic in
> the !MAP_ANON case.
>
> The reported panic involves, I'd guess, a race between fd_getfile() and
> vref():
>
> panic: vref used where vget required
> db_enter() at db_enter+0x5
> panic() at panic+0x129
> vref(ffffff03b20d29e8) at vref+0x5d
> uvn_attach(1010000,ffffff03a5879dc0) at uvn_attach+0x11d
> uvm_mmapfile(7,ffffff03a5879dc0,2,1,13,100000012) at uvm_mmapfile+0x12c
> sys_mmap(c50,ffff8000225f82a0,1) at sys_mmap+0x604
> syscall() at syscall+0x279
> --- syscall (number 198) ---
> end of kernel
>
> Removing the KERNEL_LOCK() from file mapping was out of the scope of this
> previous work, so I'd like to go back to a single KERNEL_LOCK/UNLOCK dance
> in this code path to remove any false positive.
>
> Note that this code is currently always run under KERNEL_LOCK() so this
> will only have effect once the syscall will be unlocked.
>
> ok?
Hmm, I thought fd_getfile() was fully mpsafe.
But I suppose the kernel lock needs to be grabbed before we start
looking at the vnode?
Your diff makes the locking a bit convoluted, but I suppose adding a
KERNEL_UNLOCK() before every "goto out" is worse?
> Index: uvm/uvm_mmap.c
> ===================================================================
> RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
> retrieving revision 1.161
> diff -u -p -r1.161 uvm_mmap.c
> --- uvm/uvm_mmap.c 4 Mar 2020 21:15:39 -0000 1.161
> +++ uvm/uvm_mmap.c 28 Sep 2020 09:48:26 -0000
> @@ -288,8 +288,11 @@ sys_mmap(struct proc *p, void *v, regist
>
> /* check for file mappings (i.e. not anonymous) and verify file. */
> if ((flags & MAP_ANON) == 0) {
> - if ((fp = fd_getfile(fdp, fd)) == NULL)
> - return (EBADF);
> + KERNEL_LOCK();
> + if ((fp = fd_getfile(fdp, fd)) == NULL) {
> + error = EBADF;
> + goto out;
> + }
>
> if (fp->f_type != DTYPE_VNODE) {
> error = ENODEV; /* only mmap vnodes! */
> @@ -313,6 +316,7 @@ sys_mmap(struct proc *p, void *v, regist
> flags |= MAP_ANON;
> FRELE(fp, p);
> fp = NULL;
> + KERNEL_UNLOCK();
> goto is_anon;
> }
>
> @@ -362,9 +366,7 @@ sys_mmap(struct proc *p, void *v, regist
> * EPERM.
> */
> if (fp->f_flag & FWRITE) {
> - KERNEL_LOCK();
> error = VOP_GETATTR(vp, &va, p->p_ucred, p);
> - KERNEL_UNLOCK();
> if (error)
> goto out;
> if ((va.va_flags & (IMMUTABLE|APPEND)) == 0)
> @@ -390,9 +392,9 @@ sys_mmap(struct proc *p, void *v, regist
> goto out;
> }
> }
> - KERNEL_LOCK();
> error = uvm_mmapfile(&p->p_vmspace->vm_map, &addr, size, prot,
> maxprot, flags, vp, pos, lim_cur(RLIMIT_MEMLOCK), p);
> + FRELE(fp, p);
> KERNEL_UNLOCK();
> } else { /* MAP_ANON case */
> if (fd != -1)
> @@ -428,7 +430,10 @@ is_anon: /* label for SunOS style /dev/z
> /* remember to add offset */
> *retval = (register_t)(addr + pageoff);
>
> + return (error);
> +
> out:
> + KERNEL_UNLOCK();
> if (fp)
> FRELE(fp, p);
> return (error);
>
>