ovl: skip overlayfs superblocks at global sync
authorKonstantin Khlebnikov <khlebnikov@yandex-team.ru>
Thu, 9 Apr 2020 08:29:47 +0000 (11:29 +0300)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 13 May 2020 09:11:24 +0000 (11:11 +0200)
Stacked filesystems like overlayfs has no own writeback, but they have to
forward syncfs() requests to backend for keeping data integrity.

During global sync() each overlayfs instance calls method ->sync_fs() for
backend although it itself is in global list of superblocks too.  As a
result one syscall sync() could write one superblock several times and send
multiple disk barriers.

This patch adds flag SB_I_SKIP_SYNC into sb->sb_iflags to avoid that.

Reported-by: Dmitry Monakhov <dmtrmonakhov@yandex-team.ru>
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/super.c
fs/sync.c
include/linux/fs.h

index 6e3fa96613f50d606231e52b1957f90b85e3e40c..f57aa348dcd63c56e074e4d83d5c454e8c530b08 100644 (file)
@@ -261,8 +261,8 @@ static int ovl_sync_fs(struct super_block *sb, int wait)
                return 0;
 
        /*
-        * If this is a sync(2) call or an emergency sync, all the super blocks
-        * will be iterated, including upper_sb, so no need to do anything.
+        * Not called for sync(2) call or an emergency sync (SB_I_SKIP_SYNC).
+        * All the super blocks will be iterated, including upper_sb.
         *
         * If this is a syncfs(2) call, then we do need to call
         * sync_filesystem() on upper_sb, but enough if we do it when being
@@ -1870,6 +1870,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_xattr = ovl_xattr_handlers;
        sb->s_fs_info = ofs;
        sb->s_flags |= SB_POSIXACL;
+       sb->s_iflags |= SB_I_SKIP_SYNC;
 
        err = -ENOMEM;
        root_dentry = ovl_get_root(sb, upperpath.dentry, oe);
index 4d1ff010bc5afcd6acee1e4dbd736e8bfbd9081a..16c2630ee4bf1d8eeda15bb49e1c1b309c0587a7 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -76,7 +76,8 @@ static void sync_inodes_one_sb(struct super_block *sb, void *arg)
 
 static void sync_fs_one_sb(struct super_block *sb, void *arg)
 {
-       if (!sb_rdonly(sb) && sb->s_op->sync_fs)
+       if (!sb_rdonly(sb) && !(sb->s_iflags & SB_I_SKIP_SYNC) &&
+           sb->s_op->sync_fs)
                sb->s_op->sync_fs(sb, *(int *)arg);
 }
 
index 4f6f59b4f22a807e55e479468df1f1cb7068cfdc..f186a966a36cbec428b260ef655573d015bda41b 100644 (file)
@@ -1409,6 +1409,8 @@ extern int send_sigurg(struct fown_struct *fown);
 #define SB_I_IMA_UNVERIFIABLE_SIGNATURE        0x00000020
 #define SB_I_UNTRUSTED_MOUNTER         0x00000040
 
+#define SB_I_SKIP_SYNC 0x00000100      /* Skip superblock at global sync */
+
 /* Possible states of 'frozen' field */
 enum {
        SB_UNFROZEN = 0,                /* FS is unfrozen */