• Eric Ren's avatar
    ocfs2: fix deadlock on mmapped page in ocfs2_write_begin_nolock() · c33f0785
    Eric Ren authored
    The testcase "mmaptruncate" of ocfs2-test deadlocks occasionally.
    
    In this testcase, we create a 2*CLUSTER_SIZE file and mmap() on it;
    there are 2 process repeatedly performing the following operations
    respectively: one is doing memset(mmaped_addr + 2*CLUSTER_SIZE - 1, 'a',
    1), while the another is playing ftruncate(fd, 2*CLUSTER_SIZE) and then
    ftruncate(fd, CLUSTER_SIZE) again and again.
    
    This is the backtrace when the deadlock happens:
    
       __wait_on_bit_lock+0x50/0xa0
       __lock_page+0xb7/0xc0
       ocfs2_write_begin_nolock+0x163f/0x1790 [ocfs2]
       ocfs2_page_mkwrite+0x1c7/0x2a0 [ocfs2]
       do_page_mkwrite+0x66/0xc0
       handle_mm_fault+0x685/0x1350
       __do_page_fault+0x1d8/0x4d0
       trace_do_page_fault+0x37/0xf0
       do_async_page_fault+0x19/0x70
       async_page_fault+0x28/0x30
    
    In ocfs2_write_begin_nolock(), we first grab the pages and then allocate
    disk space for this write; ocfs2_try_to_free_truncate_log() will be
    called if -ENOSPC is returned; if we're lucky to get enough clusters,
    which is usually the case, we start over again.
    
    But in ocfs2_free_write_ctxt() the target page isn't unlocked, so we
    will deadlock when trying to grab the target page again.
    
    Also, -ENOMEM might be returned in ocfs2_grab_pages_for_write().
    Another deadlock will happen in __do_page_mkwrite() if
    ocfs2_page_mkwrite() returns non-VM_FAULT_LOCKED, and along with a
    locked target page.
    
    These two errors fail on the same path, so fix them by unlocking the
    target page manually before ocfs2_free_write_ctxt().
    
    Jan Kara helps me clear out the JBD2 part, and suggest the hint for root
    cause.
    
    Changes since v1:
    1. Also put ENOMEM error case into consideration.
    
    Link: http://lkml.kernel.org/r/1474173902-32075-1-git-send-email-zren@suse.comSigned-off-by: default avatarEric Ren <zren@suse.com>
    Reviewed-by: default avatarHe Gang <ghe@suse.com>
    Acked-by: default avatarJoseph Qi <joseph.qi@huawei.com>
    Cc: Mark Fasheh <mfasheh@suse.de>
    Cc: Joel Becker <jlbec@evilplan.org>
    Cc: Junxiao Bi <junxiao.bi@oracle.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    c33f0785
Name
Last commit
Last update
..
cluster Loading commit data...
dlm Loading commit data...
dlmfs Loading commit data...
Kconfig Loading commit data...
Makefile Loading commit data...
acl.c Loading commit data...
acl.h Loading commit data...
alloc.c Loading commit data...
alloc.h Loading commit data...
aops.c Loading commit data...
aops.h Loading commit data...
blockcheck.c Loading commit data...
blockcheck.h Loading commit data...
buffer_head_io.c Loading commit data...
buffer_head_io.h Loading commit data...
dcache.c Loading commit data...
dcache.h Loading commit data...
dir.c Loading commit data...
dir.h Loading commit data...
dlmglue.c Loading commit data...
dlmglue.h Loading commit data...
export.c Loading commit data...
export.h Loading commit data...
extent_map.c Loading commit data...
extent_map.h Loading commit data...
file.c Loading commit data...
file.h Loading commit data...
filecheck.c Loading commit data...
filecheck.h Loading commit data...
heartbeat.c Loading commit data...
heartbeat.h Loading commit data...
inode.c Loading commit data...
inode.h Loading commit data...
ioctl.c Loading commit data...
ioctl.h Loading commit data...
journal.c Loading commit data...
journal.h Loading commit data...
localalloc.c Loading commit data...
localalloc.h Loading commit data...
locks.c Loading commit data...
locks.h Loading commit data...
mmap.c Loading commit data...
mmap.h Loading commit data...
move_extents.c Loading commit data...
move_extents.h Loading commit data...
namei.c Loading commit data...
namei.h Loading commit data...
ocfs1_fs_compat.h Loading commit data...
ocfs2.h Loading commit data...
ocfs2_fs.h Loading commit data...
ocfs2_ioctl.h Loading commit data...
ocfs2_lockid.h Loading commit data...
ocfs2_lockingver.h Loading commit data...
ocfs2_trace.h Loading commit data...
quota.h Loading commit data...
quota_global.c Loading commit data...
quota_local.c Loading commit data...
refcounttree.c Loading commit data...
refcounttree.h Loading commit data...
reservations.c Loading commit data...
reservations.h Loading commit data...
resize.c Loading commit data...
resize.h Loading commit data...
slot_map.c Loading commit data...
slot_map.h Loading commit data...
stack_o2cb.c Loading commit data...
stack_user.c Loading commit data...
stackglue.c Loading commit data...
stackglue.h Loading commit data...
suballoc.c Loading commit data...
suballoc.h Loading commit data...
super.c Loading commit data...
super.h Loading commit data...
symlink.c Loading commit data...
symlink.h Loading commit data...
sysfile.c Loading commit data...
sysfile.h Loading commit data...
uptodate.c Loading commit data...
uptodate.h Loading commit data...
xattr.c Loading commit data...
xattr.h Loading commit data...