linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Omar Sandoval <osandov@osandov.com>
To: Alexander Viro <viro@zeniv.linux.org.uk>,
	Andrew Morton <akpm@linux-foundation.org>,
	Chris Mason <clm@fb.com>, Josef Bacik <jbacik@fb.com>,
	Trond Myklebust <trond.myklebust@primarydata.com>,
	Christoph Hellwig <hch@infradead.org>,
	David Sterba <dsterba@suse.cz>,
	linux-btrfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-mm@kvack.org, linux-nfs@vger.kernel.org,
	linux-kernel@vger.kernel.org
Cc: Omar Sandoval <osandov@osandov.com>
Subject: [RFC PATCH v3 5/7] btrfs: prevent ioctls from interfering with a swap file
Date: Tue,  9 Dec 2014 17:45:46 -0800	[thread overview]
Message-ID: <a0ff3435124c2150effb6681d529d56032c711f8.1418173063.git.osandov@osandov.com> (raw)
In-Reply-To: <cover.1418173063.git.osandov@osandov.com>
In-Reply-To: <cover.1418173063.git.osandov@osandov.com>

There are several ioctls which can work around constraints enforced by
btrfs_swap_activate and lead to an unsafe situation. We cannot do any of
the following on an active swap file in order to avoid creating
compressed or shared extents:

- chattr -C or +c
- snapshot create
- defrag
- clone
- dedup

Signed-off-by: Omar Sandoval <osandov@osandov.com>
---
 fs/btrfs/ctree.h   |  3 +++
 fs/btrfs/disk-io.c |  1 +
 fs/btrfs/ioctl.c   | 35 +++++++++++++++++++++++++++++++----
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fe69edd..38979b9 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1891,6 +1891,9 @@ struct btrfs_root {
 	int send_in_progress;
 	struct btrfs_subvolume_writers *subv_writers;
 	atomic_t will_be_snapshoted;
+
+	/* Number of active swapfiles */
+	atomic_t nr_swapfiles;
 };
 
 struct btrfs_ioctl_defrag_range_args {
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1bf9f89..60094c4 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1265,6 +1265,7 @@ static void __setup_root(u32 nodesize, u32 sectorsize, u32 stripesize,
 	atomic_set(&root->orphan_inodes, 0);
 	atomic_set(&root->refs, 1);
 	atomic_set(&root->will_be_snapshoted, 0);
+	atomic_set(&root->nr_swapfiles, 0);
 	root->log_transid = 0;
 	root->log_transid_committed = -1;
 	root->last_log_commit = 0;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4399f0c..18fa95c 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -291,9 +291,11 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 		} else {
 			ip->flags |= BTRFS_INODE_NODATACOW;
 		}
-	} else {
+	} else if (!IS_SWAPFILE(inode)) {
 		/*
-		 * Revert back under same assuptions as above
+		 * Revert back under same assumptions as above. swap_activate
+		 * checks that we don't swapon a copy-on-write file, but we also
+		 * make sure that it doesn't become copy-on-write here.
 		 */
 		if (S_ISREG(mode)) {
 			if (inode->i_size == 0)
@@ -316,7 +318,12 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 		ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0);
 		if (ret && ret != -ENODATA)
 			goto out_drop;
-	} else if (flags & FS_COMPR_FL) {
+	} else if (flags & FS_COMPR_FL && !IS_SWAPFILE(inode)) {
+		/*
+		 * Like nodatacow, swap_activate checks that we don't swapon a
+		 * compressed file, so we shouldn't let it become compressed.
+		 */
+
 		const char *comp;
 
 		ip->flags |= BTRFS_INODE_COMPRESS;
@@ -330,7 +337,6 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 				     comp, strlen(comp), 0);
 		if (ret)
 			goto out_drop;
-
 	} else {
 		ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0);
 		if (ret && ret != -ENODATA)
@@ -647,6 +653,12 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
 	if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
 		return -EINVAL;
 
+	if (atomic_read(&root->nr_swapfiles)) {
+		btrfs_err(root->fs_info,
+			  "cannot create snapshot with active swapfile");
+		return -ETXTBSY;
+	}
+
 	atomic_inc(&root->will_be_snapshoted);
 	smp_mb__after_atomic();
 	btrfs_wait_nocow_write(root);
@@ -1292,6 +1304,12 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
 			compress_type = range->compress_type;
 	}
 
+	mutex_lock(&inode->i_mutex);
+	ret = IS_SWAPFILE(inode) ? -ETXTBSY : 0;
+	mutex_unlock(&inode->i_mutex);
+	if (ret)
+		return ret;
+
 	if (extent_thresh == 0)
 		extent_thresh = 256 * 1024;
 
@@ -2927,6 +2945,11 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
 
 	btrfs_double_lock(src, loff, dst, dst_loff, len);
 
+	if (IS_SWAPFILE(src) || IS_SWAPFILE(dst)) {
+		ret = -ETXTBSY;
+		goto out_unlock;
+	}
+
 	ret = extent_same_check_offsets(src, loff, len);
 	if (ret)
 		goto out_unlock;
@@ -3644,6 +3667,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 		mutex_lock(&src->i_mutex);
 	}
 
+	ret = -ETXTBSY;
+	if (IS_SWAPFILE(src) || IS_SWAPFILE(inode))
+		goto out_unlock;
+
 	/* determine range to clone */
 	ret = -EINVAL;
 	if (off + len > src->i_size || off + len < off)
-- 
2.1.3

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  parent reply	other threads:[~2014-12-10  1:46 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-10  1:45 [RFC PATCH v3 0/7] btrfs: implement swap file support Omar Sandoval
2014-12-10  1:45 ` [RFC PATCH v3 1/7] direct-io: don't dirty ITER_BVEC pages on read Omar Sandoval
2014-12-10  1:45 ` [RFC PATCH v3 2/7] nfs: don't dirty ITER_BVEC pages read through direct I/O Omar Sandoval
2014-12-10  1:45 ` [RFC PATCH v3 3/7] swap: use direct I/O for SWP_FILE swap_readpage Omar Sandoval
2014-12-10  1:45 ` [RFC PATCH v3 4/7] vfs: update swap_{,de}activate documentation Omar Sandoval
2014-12-10  1:45 ` Omar Sandoval [this message]
2014-12-10  1:45 ` [RFC PATCH v3 6/7] btrfs: add EXTENT_FLAG_SWAPFILE Omar Sandoval
2014-12-12 10:32   ` David Sterba
2014-12-10  1:45 ` [RFC PATCH v3 7/7] btrfs: enable swap file support Omar Sandoval
2014-12-12 10:51   ` David Sterba
2014-12-12 20:00     ` Omar Sandoval
2014-12-12 10:32 ` [RFC PATCH v3 0/7] btrfs: implement " David Sterba
2014-12-12 20:15   ` 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=a0ff3435124c2150effb6681d529d56032c711f8.1418173063.git.osandov@osandov.com \
    --to=osandov@osandov.com \
    --cc=akpm@linux-foundation.org \
    --cc=clm@fb.com \
    --cc=dsterba@suse.cz \
    --cc=hch@infradead.org \
    --cc=jbacik@fb.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=trond.myklebust@primarydata.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox