Bug 101951

Summary: Overlayfs on top of btrfs causes kernel oops + freeze
Product: File System Reporter: Francesco Frassinelli (fraph24)
Component: btrfsAssignee: David Sterba (dsterba)
Status: RESOLVED CODE_FIX    
Severity: normal CC: colin.king, dsterba, fraph24, kernel, kewav53608, rauter.gabriel, schmittjoh, szg00000
Priority: P1    
Hardware: x86-64   
OS: Linux   
Kernel Version: 4.2.0-0.rc2.git2 Subsystem:
Regression: No Bisected commit-id:
Attachments: kernel oops log

Description Francesco Frassinelli 2015-07-25 23:17:23 UTC
Created attachment 183641 [details]
kernel oops log

How to reproduce:
$ mkdir {lower,upper,work,overlay}
$ uname > lower/uname
# mount overlay -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay
$ # edit overlay/uname

Results:
Kernel oops, screen freezes.
Comment 1 Gabriel Rauter 2015-09-17 15:22:21 UTC
I have the same problem although i am using overlay while being in a docker container. Host fs is btrfs on arch linux kernel 4.2.0, guest docker image ubuntu:wily.
kernel oops log can be found here
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1496438/comments/2
Comment 2 Colin Ian King 2016-02-10 16:51:25 UTC
I've debugged this a bit, the failure occurs on an atomic_inc on root, when root is NULL, cf:

atomic_inc(&root->log_batch);
Comment 3 Colin Ian King 2016-02-16 11:01:18 UTC
bisected: 4bacc9c9234c7c8eec44f5ed4e960d9f96fa0f01 is the first bad commit

commit 4bacc9c9234c7c8eec44f5ed4e960d9f96fa0f01
Author: David Howells <dhowells@redhat.com>
Date: Thu Jun 18 14:32:31 2015 +0100

    overlayfs: Make f_path always point to the overlay and f_inode to the underlay
Comment 4 Colin Ian King 2016-02-16 15:24:24 UTC
The following stops the issue. I'm not sure if it is the correct fix though.

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 098bb8f..5e5df8b 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1884,7 +1884,7 @@ static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end)
 int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct dentry *dentry = file->f_path.dentry;
-       struct inode *inode = d_inode(dentry);
+       struct inode *inode = file_inode(file);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
        struct btrfs_log_ctx ctx;
Comment 5 Colin Ian King 2016-02-16 15:41:10 UTC
Commit 4bacc9c9234c7c8eec44f5ed4e960d9f96fa0f01 ("overlayfs: Make f_path
always point to the overlay and f_inode to the underlay") resulted in an
issue when using a combination of btrfs and overlayfs.  This is
noticeable when doing a fsync() on a file in a chroot with overlayfs on
top of btrfs; we hit a kernel oops in btrfs_sync_file() on
atomic_inc(&root->log_batch) because root is NULL.

I've debugged this further and found that in btrfs_sync_file():

	struct inode *inode = d_inode(dentry);

does not return the inode I expected when using the stacked overlay fs,
where as:

	struct inode *inode = file_inode(file);

does.

However, I'm not well at all well versed in btrfs, so I am not confident
this is a actually correct.  Any comments?
Comment 6 David Sterba 2019-05-21 12:33:42 UTC
Fixed by de17e793b104d690e1d "btrfs: fix crash/invalid memory access on fsync when using overlayfs", in 4.6.