FreeBSDDesktop / DEPRECATED-freebsd-base-graphics

Fork of FreeBSD's base repository to work on graphics-stack-related projects
Other
49 stars 13 forks source link

[test case] panic: vm_page_free_toq: freeing mapped page #120

Closed yanko-yankulov closed 7 years ago

yanko-yankulov commented 7 years ago

Hi all,

I stumbled on the following panic on drm-next (3025e6199432c5748973776e322a207b8f39b200), again playing with intel-gpu-tests. Providing a reduced test case below ( as the intel test, would not trigger the issue on drm-next. It does with a patch implementing #117 ). The reduced test case triggers always on drm-next.

Have no clue what is actually happening. My guess is that is somehow caused by the code in i915_gem_mmap_ioctl, but really no idea for the moment.

panic: vm_page_free_toq: freeing mapped page 0xfffff80257574288
cpuid = 2
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe0231692000
kdb_backtrace() at kdb_backtrace+0x53/frame 0xfffffe02316920d0
vpanic() at vpanic+0x249/frame 0xfffffe02316921a0
kassert_panic() at kassert_panic+0xc4/frame 0xfffffe0231692210
vm_page_free_toq() at vm_page_free_toq+0x216/frame 0xfffffe0231692230
vm_object_terminate() at vm_object_terminate+0x199/frame 0xfffffe0231692270
vm_object_deallocate() at vm_object_deallocate+0x2d9/frame 0xfffffe02316922e0
linux_file_free() at linux_file_free+0x3e/frame 0xfffffe0231692300
drm_gem_object_release() at drm_gem_object_release+0xc1/frame 0xfffffe0231692330
i915_gem_free_object() at i915_gem_free_object+0x178/frame 0xfffffe0231692360
drm_gem_object_unreference_unlocked() at drm_gem_object_unreference_unlocked+0xe4/frame 0xfffffe0231692390
drm_gem_object_release_handle() at drm_gem_object_release_handle+0xd3/frame 0xfffffe02316923c0
idr_for_each_layer() at idr_for_each_layer+0x72/frame 0xfffffe0231692400
drm_gem_release() at drm_gem_release+0x1f/frame 0xfffffe0231692420
drm_release() at drm_release+0x29b/frame 0xfffffe0231692470
linux_file_dtor() at linux_file_dtor+0x2d/frame 0xfffffe0231692490
devfs_destroy_cdevpriv() at devfs_destroy_cdevpriv+0x8b/frame 0xfffffe02316924b0
linux_dev_close() at linux_dev_close+0x35/frame 0xfffffe02316924d0
devfs_close() at devfs_close+0x223/frame 0xfffffe0231692540
VOP_CLOSE_APV() at VOP_CLOSE_APV+0xda/frame 0xfffffe0231692570
vn_close() at vn_close+0xe4/frame 0xfffffe02316925e0
vn_closefile() at vn_closefile+0x39/frame 0xfffffe0231692660
devfs_close_f() at devfs_close_f+0x2c/frame 0xfffffe0231692690
_fdrop() at _fdrop+0x1a/frame 0xfffffe02316926b0
closef() at closef+0x1f0/frame 0xfffffe0231692740
fdescfree_fds() at fdescfree_fds+0x7d/frame 0xfffffe0231692780
fdescfree() at fdescfree+0x44e/frame 0xfffffe0231692840
exit1() at exit1+0x4ec/frame 0xfffffe02316928a0
sys_sys_exit() at sys_sys_exit+0xd/frame 0xfffffe02316928b0
syscallenter() at syscallenter+0x54f/frame 0xfffffe0231692980
amd64_syscall() at amd64_syscall+0x2a/frame 0xfffffe0231692ab0
Xfast_syscall() at Xfast_syscall+0xfb/frame 0xfffffe0231692ab0

Test case to trigger it:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include <sys/mman.h>
#include <libdrm/i915_drm.h>

int main(void)
{
        int fd = open("/dev/dri/card0", O_RDWR);
        unsigned i;
        assert( fd != -1 );

        uint32_t handle;

        {
                struct drm_i915_gem_create create = {
                        .size = 512*512*4,
                };
                int res = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create );
                if( res != 0 )
                {
                        perror("GEM_CREATE");
                        exit(1);
                }
                handle = create.handle;
        }

        {
                struct drm_i915_gem_mmap mmap_arg = {
                        .handle = handle,
                        .offset = 0,
                        .size = 512*512*4,
                };
                int res = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg );
                assert( res == 0 );
                uint32_t *ptr = (void*)mmap_arg.addr_ptr;
                //memset( ptr, 0, 4096 );
                uint32_t k;
                for( i = 0; i < (mmap_arg.size ) / 4; i++ )
                        k += ptr[i];
                assert( k == 0 || k != 0 );
                munmap((void*)ptr, mmap_arg.size);
        }

        {
                struct drm_i915_gem_mmap mmap_arg = {
                        .handle = handle,
                        .offset = 1007616,
                        .size = 512*512*4 - 1007616,
                };
                int res = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg );
                assert( res == 0 );
                uint32_t *ptr = (void*)mmap_arg.addr_ptr;
                uint32_t k;
                for( i = 0; i < (mmap_arg.size) / 4; i++ )
                        k += ptr[i];
                assert( k == 0 || k != 0 );
                munmap((void*)ptr, mmap_arg.size);
        }
}
mattmacy commented 7 years ago

I can trigger a similar panic in both drm-next and HEAD by running one of the WebGL examples. Kostik doesn't appear to have any idea how to fix as I reported it six months ago.

yanko-yankulov commented 7 years ago

Wow. OK. Thanks.

yanko-yankulov commented 7 years ago

Hi @mattmacy,

Kib has committed the fix for this to master (568d99bbad1b295d9476cbbc4f8b5cb83e0a7973).

I have one more question on this one though. The reason why we are hitting the upstream bug, and the rest of the system does not, is that MAP_SHARED mappings usually get MAP_PREFAULT_PARTIAL flag, and we don't add it the call to vm_map_find from i915_gem_mmap_ioctl. With prefault_partial hitting the underlying bug, while not impossible, gets pretty hard.

This got me thinking do we have some particular reason to not want the prefaulting there? I couldn't come up with a reason why we wouldn't , so just dropping the question.

Thanks, Yanko