From: Omar Sandoval <osandov@osandov.com>
To: linux-fsdevel@vger.kernel.org, Al Viro <viro@zeniv.linux.org.uk>
Cc: kernel-team@fb.com, "Eric W . Biederman" <ebiederm@xmission.com>,
Tejun Heo <tj@kernel.org>
Subject: Re: [PATCH] fs: only sync() superblocks reachable from the current namespace
Date: Fri, 26 Jan 2018 15:00:49 -0800 [thread overview]
Message-ID: <20180126230049.GC19033@vader.DHCP.thefacebook.com> (raw)
In-Reply-To: <05434cda5cc3b461b5d70467b094904ad23fdc11.1517007510.git.osandov@fb.com>
On Fri, Jan 26, 2018 at 02:58:39PM -0800, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
>
> Currently, the sync() syscall is system-wide, so any process in a
> container can cause significant I/O stalls across the system by calling
> sync(). This is even true for filesystems which are not accessible in
> the process' mount namespace. This patch scopes sync() to only write out
> filesystems reachable in the current mount namespace, except for the
> initial mount namespace, which still syncs everything to avoid
> surprises. This fixes the broken isolation we were seeing here.
>
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
> fs/sync.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++--------------
> 1 file changed, 51 insertions(+), 14 deletions(-)
>
> diff --git a/fs/sync.c b/fs/sync.c
> index 6e0a2cbaf6de..bde1e3196298 100644
> --- a/fs/sync.c
> +++ b/fs/sync.c
> @@ -17,6 +17,7 @@
> #include <linux/quotaops.h>
> #include <linux/backing-dev.h>
> #include "internal.h"
> +#include "mount.h"
>
> #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
> SYNC_FILE_RANGE_WAIT_AFTER)
> @@ -68,16 +69,46 @@ int sync_filesystem(struct super_block *sb)
> }
> EXPORT_SYMBOL(sync_filesystem);
>
> -static void sync_inodes_one_sb(struct super_block *sb, void *arg)
> +struct sb_sync {
> + /*
> + * Only sync superblocks reachable from this namespace. If NULL, sync
> + * everything.
> + */
> + struct mnt_namespace *mnt_ns;
> +
> + /* ->sync_fs() wait argument. */
> + int wait;
> +};
> +
> +static int sb_reachable(struct super_block *sb, struct mnt_namespace *mnt_ns)
> +{
> + struct mount *mnt;
> +
> + if (!mnt_ns)
> + return 1;
> +
> + list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
> + if (mnt->mnt_ns == mnt_ns)
> + return 1;
> + }
Sigh, of course, I forgot to grab the proper locks here. Will send a v2.
> + return 0;
> +}
> +
> +static void sync_inodes_one_sb(struct super_block *sb, void *p)
> {
> - if (!sb_rdonly(sb))
> + struct sb_sync *arg = p;
> +
> + if (!sb_rdonly(sb) && sb_reachable(sb, arg->mnt_ns))
> sync_inodes_sb(sb);
> }
>
> -static void sync_fs_one_sb(struct super_block *sb, void *arg)
> +static void sync_fs_one_sb(struct super_block *sb, void *p)
> {
> - if (!sb_rdonly(sb) && sb->s_op->sync_fs)
> - sb->s_op->sync_fs(sb, *(int *)arg);
> + struct sb_sync *arg = p;
> +
> + if (!sb_rdonly(sb) && sb_reachable(sb, arg->mnt_ns) &&
> + sb->s_op->sync_fs)
> + sb->s_op->sync_fs(sb, arg->wait);
> }
>
> static void fdatawrite_one_bdev(struct block_device *bdev, void *arg)
> @@ -107,12 +138,18 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
> */
> SYSCALL_DEFINE0(sync)
> {
> - int nowait = 0, wait = 1;
> + struct sb_sync arg = {
> + .mnt_ns = current->nsproxy->mnt_ns,
> + };
> +
> + if (arg.mnt_ns == init_task.nsproxy->mnt_ns)
> + arg.mnt_ns = NULL;
>
> wakeup_flusher_threads(WB_REASON_SYNC);
> - iterate_supers(sync_inodes_one_sb, NULL);
> - iterate_supers(sync_fs_one_sb, &nowait);
> - iterate_supers(sync_fs_one_sb, &wait);
> + iterate_supers(sync_inodes_one_sb, &arg);
> + iterate_supers(sync_fs_one_sb, &arg);
> + arg.wait = 1;
> + iterate_supers(sync_fs_one_sb, &arg);
> iterate_bdevs(fdatawrite_one_bdev, NULL);
> iterate_bdevs(fdatawait_one_bdev, NULL);
> if (unlikely(laptop_mode))
> @@ -122,17 +159,17 @@ SYSCALL_DEFINE0(sync)
>
> static void do_sync_work(struct work_struct *work)
> {
> - int nowait = 0;
> + struct sb_sync arg = {};
>
> /*
> * Sync twice to reduce the possibility we skipped some inodes / pages
> * because they were temporarily locked
> */
> - iterate_supers(sync_inodes_one_sb, &nowait);
> - iterate_supers(sync_fs_one_sb, &nowait);
> + iterate_supers(sync_inodes_one_sb, &arg);
> + iterate_supers(sync_fs_one_sb, &arg);
> iterate_bdevs(fdatawrite_one_bdev, NULL);
> - iterate_supers(sync_inodes_one_sb, &nowait);
> - iterate_supers(sync_fs_one_sb, &nowait);
> + iterate_supers(sync_inodes_one_sb, &arg);
> + iterate_supers(sync_fs_one_sb, &arg);
> iterate_bdevs(fdatawrite_one_bdev, NULL);
> printk("Emergency Sync complete\n");
> kfree(work);
> --
> 2.16.1
>
next prev parent reply other threads:[~2018-01-26 23:00 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-26 22:58 [PATCH] fs: only sync() superblocks reachable from the current namespace Omar Sandoval
2018-01-26 23:00 ` Omar Sandoval [this message]
2018-01-26 23:13 ` Al Viro
2018-01-26 23:17 ` Al Viro
2018-01-26 23:46 ` Omar Sandoval
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180126230049.GC19033@vader.DHCP.thefacebook.com \
--to=osandov@osandov.com \
--cc=ebiederm@xmission.com \
--cc=kernel-team@fb.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=tj@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.