Some filesystem, like btrfs, supports mounting cloned images, but assign random UUIDs for them to avoid conflicts. This breaks overlayfs "index" check, given that every time the same image is mounted, it get's assigned a new UUID. Fix this assigning the disk UUID for filesystem that implements the export operation get_disk_uuid(), so overlayfs check is also against the same value. Signed-off-by: André Almeida --- fs/overlayfs/copy_up.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 758611ee4475..8551681fffd3 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -421,8 +421,26 @@ struct ovl_fh *ovl_encode_real_fh(struct ovl_fs *ofs, struct inode *realinode, struct ovl_fh *fh; int fh_type, dwords; int buflen = MAX_HANDLE_SZ; - uuid_t *uuid = &realinode->i_sb->s_uuid; - int err; + struct super_block *real_sb = realinode->i_sb; + uuid_t *uuid = &real_sb->s_uuid, real_uuid; + u32 len = sizeof(uuid_t); + int err, ret; + u64 offset; + + /* + * Some filesystems that support cloned devices may expose random UUIDs + * for userspace, which will cause the upper root origin check to fail + * during a remount. To avoid this, store the real disk UUID. + * + * ENODATA means that the filesystem implements get_disk_uuid(), but + * this instance is using the real UUID so we can skip the operation. + */ + if (real_sb->s_export_op && real_sb->s_export_op->get_disk_uuid) { + ret = real_sb->s_export_op->get_disk_uuid(real_sb, real_uuid.b, &len, &offset); + + if (!ret || ret != ENODATA) + uuid = &real_uuid; + } /* Make sure the real fid stays 32bit aligned */ BUILD_BUG_ON(OVL_FH_FID_OFFSET % 4); -- 2.52.0