]>
Commit | Line | Data |
---|---|---|
5032628c GKH |
1 | From 7b4cc9787fe35b3ee2dfb1c35e22eafc32e00c33 Mon Sep 17 00:00:00 2001 |
2 | From: Eric Biggers <ebiggers@google.com> | |
3 | Date: Sun, 30 Apr 2017 00:10:50 -0400 | |
4 | Subject: ext4: evict inline data when writing to memory map | |
5 | ||
6 | From: Eric Biggers <ebiggers@google.com> | |
7 | ||
8 | commit 7b4cc9787fe35b3ee2dfb1c35e22eafc32e00c33 upstream. | |
9 | ||
10 | Currently the case of writing via mmap to a file with inline data is not | |
11 | handled. This is maybe a rare case since it requires a writable memory | |
12 | map of a very small file, but it is trivial to trigger with on | |
13 | inline_data filesystem, and it causes the | |
14 | 'BUG_ON(ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA));' in | |
15 | ext4_writepages() to be hit: | |
16 | ||
17 | mkfs.ext4 -O inline_data /dev/vdb | |
18 | mount /dev/vdb /mnt | |
19 | xfs_io -f /mnt/file \ | |
20 | -c 'pwrite 0 1' \ | |
21 | -c 'mmap -w 0 1m' \ | |
22 | -c 'mwrite 0 1' \ | |
23 | -c 'fsync' | |
24 | ||
25 | kernel BUG at fs/ext4/inode.c:2723! | |
26 | invalid opcode: 0000 [#1] SMP | |
27 | CPU: 1 PID: 2532 Comm: xfs_io Not tainted 4.11.0-rc1-xfstests-00301-g071d9acf3d1f #633 | |
28 | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-20170228_101828-anatol 04/01/2014 | |
29 | task: ffff88003d3a8040 task.stack: ffffc90000300000 | |
30 | RIP: 0010:ext4_writepages+0xc89/0xf8a | |
31 | RSP: 0018:ffffc90000303ca0 EFLAGS: 00010283 | |
32 | RAX: 0000028410000000 RBX: ffff8800383fa3b0 RCX: ffffffff812afcdc | |
33 | RDX: 00000a9d00000246 RSI: ffffffff81e660e0 RDI: 0000000000000246 | |
34 | RBP: ffffc90000303dc0 R08: 0000000000000002 R09: 869618e8f99b4fa5 | |
35 | R10: 00000000852287a2 R11: 00000000a03b49f4 R12: ffff88003808e698 | |
36 | R13: 0000000000000000 R14: 7fffffffffffffff R15: 7fffffffffffffff | |
37 | FS: 00007fd3e53094c0(0000) GS:ffff88003e400000(0000) knlGS:0000000000000000 | |
38 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | |
39 | CR2: 00007fd3e4c51000 CR3: 000000003d554000 CR4: 00000000003406e0 | |
40 | Call Trace: | |
41 | ? _raw_spin_unlock+0x27/0x2a | |
42 | ? kvm_clock_read+0x1e/0x20 | |
43 | do_writepages+0x23/0x2c | |
44 | ? do_writepages+0x23/0x2c | |
45 | __filemap_fdatawrite_range+0x80/0x87 | |
46 | filemap_write_and_wait_range+0x67/0x8c | |
47 | ext4_sync_file+0x20e/0x472 | |
48 | vfs_fsync_range+0x8e/0x9f | |
49 | ? syscall_trace_enter+0x25b/0x2d0 | |
50 | vfs_fsync+0x1c/0x1e | |
51 | do_fsync+0x31/0x4a | |
52 | SyS_fsync+0x10/0x14 | |
53 | do_syscall_64+0x69/0x131 | |
54 | entry_SYSCALL64_slow_path+0x25/0x25 | |
55 | ||
56 | We could try to be smart and keep the inline data in this case, or at | |
57 | least support delayed allocation when allocating the block, but these | |
58 | solutions would be more complicated and don't seem worthwhile given how | |
59 | rare this case seems to be. So just fix the bug by calling | |
60 | ext4_convert_inline_data() when we're asked to make a page writable, so | |
61 | that any inline data gets evicted, with the block allocated immediately. | |
62 | ||
63 | Reported-by: Nick Alcock <nick.alcock@oracle.com> | |
64 | Reviewed-by: Andreas Dilger <adilger@dilger.ca> | |
65 | Signed-off-by: Eric Biggers <ebiggers@google.com> | |
66 | Signed-off-by: Theodore Ts'o <tytso@mit.edu> | |
67 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
68 | ||
69 | --- | |
70 | fs/ext4/inode.c | 5 +++++ | |
71 | 1 file changed, 5 insertions(+) | |
72 | ||
73 | --- a/fs/ext4/inode.c | |
74 | +++ b/fs/ext4/inode.c | |
75 | @@ -5874,6 +5874,11 @@ int ext4_page_mkwrite(struct vm_fault *v | |
76 | file_update_time(vma->vm_file); | |
77 | ||
78 | down_read(&EXT4_I(inode)->i_mmap_sem); | |
79 | + | |
80 | + ret = ext4_convert_inline_data(inode); | |
81 | + if (ret) | |
82 | + goto out_ret; | |
83 | + | |
84 | /* Delalloc case is easy... */ | |
85 | if (test_opt(inode->i_sb, DELALLOC) && | |
86 | !ext4_should_journal_data(inode) && |