All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anand Jain <anand.jain@oracle.com>
To: linux-btrfs@vger.kernel.org
Subject: [PATCH 4/4 RESEND] btrfs: fix property validate fail should not increment generation
Date: Tue,  2 Apr 2019 18:07:42 +0800	[thread overview]
Message-ID: <20190402100742.8355-6-anand.jain@oracle.com> (raw)
In-Reply-To: <20190402100742.8355-1-anand.jain@oracle.com>

When the property fails to pass the prop_handlers::validate() check, the
thread should exit with no changes in the kernel, but as we are starting
the transaction too early, we have just updated the generation even if
there is no change.

For example:
btrfs prop get /btrfs compression
 compression=lzo
sync
btrfs in dump-super /dev/sdb | grep "^generation"
 generation		32

Try to set an incomplete compression type

btrfs prop set /btrfs compression zli
  ERROR: failed to set compression for /btrfs: Invalid argument
sync

Set failed but generation is incremented
btrfs in dump-super /dev/sdb | grep "^generation"
 generation		33  <--

Fix it by collapsing btrfs_set_prop_trans() into btrfs_set_prop(), which
provides flexibility to start the transaction after the
prop_handlers::validate() has been checked.

As of now if the prop_handlers::apply() fails then we still increment
the generation, but if there is strong prop_handlers::validate() then
the prop_handlers::apply() can never fail.

Signed-off-by: Anand Jain <anand.jain@oracle.com>
---
 fs/btrfs/ioctl.c | 10 ++++------
 fs/btrfs/props.c | 59 +++++++++++++++++++++++++-------------------------------
 fs/btrfs/props.h |  4 ++--
 fs/btrfs/xattr.c |  2 +-
 4 files changed, 33 insertions(+), 42 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 28ee9fe6edb4..0eeaf9a68082 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -284,8 +284,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 		binode->flags &= ~BTRFS_INODE_COMPRESS;
 		binode->flags |= BTRFS_INODE_NOCOMPRESS;
 
-		ret = btrfs_set_prop_trans(inode, "btrfs.compression", NULL,
-					   0, 0);
+		ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0);
 		if (ret && ret != -ENODATA)
 			goto out_drop;
 	} else if (fsflags & FS_COMPR_FL) {
@@ -303,14 +302,13 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 		if (!comp || comp[0] == 0)
 			comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
 
-		ret = btrfs_set_prop_trans(inode, "btrfs.compression", comp,
-					   strlen(comp), 0);
+		ret = btrfs_set_prop(inode, "btrfs.compression", comp,
+				     strlen(comp), 0);
 		if (ret)
 			goto out_drop;
 
 	} else {
-		ret = btrfs_set_prop_trans(inode, "btrfs.compression", NULL,
-					   0, 0);
+		ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0);
 		if (ret && ret != -ENODATA)
 			goto out_drop;
 		binode->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index fb84e76f3b1d..99fa2459ba61 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -56,11 +56,12 @@ static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash)
 	return NULL;
 }
 
-static int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
-			  const char *name, const char *value, size_t value_len,
-			  int flags)
+int btrfs_set_prop(struct inode *inode, const char *name, const char *value,
+		   size_t value_len, int flags)
 {
+	struct btrfs_root *root = BTRFS_I(inode)->root;
 	const struct prop_handler *handler;
+	struct btrfs_trans_handle *trans;
 	int ret;
 
 	if (btrfs_root_readonly(BTRFS_I(inode)->root))
@@ -74,50 +75,40 @@ static int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
 		return -EINVAL;
 
 	if (value_len == 0) {
+		/* Its called to reset the property */
+		trans = btrfs_start_transaction(root, 2);
+		if (IS_ERR(trans))
+			return PTR_ERR(trans);
+
 		ret = btrfs_setxattr(trans, inode, handler->xattr_name,
 				       NULL, 0, flags);
-		if (ret)
-			return ret;
-
-		ret = handler->apply(inode, NULL, 0);
-		ASSERT(ret == 0);
-
-		return ret;
+		if (!ret) {
+			ret = handler->apply(inode, NULL, 0);
+			ASSERT(ret == 0);
+		}
+		goto out;
 	}
 
 	ret = handler->validate(value, value_len);
 	if (ret)
 		return ret;
+
+	trans = btrfs_start_transaction(root, 2);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
+
 	ret = btrfs_setxattr(trans, inode, handler->xattr_name,
 			       value, value_len, flags);
 	if (ret)
-		return ret;
+		goto out;
+
 	ret = handler->apply(inode, value, value_len);
 	if (ret) {
+		/* Apply failed. Reset the property. */
 		btrfs_setxattr(trans, inode, handler->xattr_name,
 				 NULL, 0, flags);
-		return ret;
-	}
-
-	set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
-
-	return 0;
-}
-
-int btrfs_set_prop_trans(struct inode *inode, const char *name,
-			 const char *value, size_t value_len, int flags)
-{
-	struct btrfs_root *root = BTRFS_I(inode)->root;
-	struct btrfs_trans_handle *trans;
-	int ret;
-
-	trans = btrfs_start_transaction(root, 2);
-	if (IS_ERR(trans))
-		return PTR_ERR(trans);
-
-	ret = btrfs_set_prop(trans, inode, name, value, value_len, flags);
-
-	if (!ret) {
+	} else {
+		set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
 		inode_inc_iversion(inode);
 		inode->i_ctime = current_time(inode);
 		set_bit(BTRFS_INODE_COPY_EVERYTHING,
@@ -125,6 +116,8 @@ int btrfs_set_prop_trans(struct inode *inode, const char *name,
 		ret = btrfs_update_inode(trans, root, inode);
 		BUG_ON(ret);
 	}
+
+out:
 	btrfs_end_transaction(trans);
 	return ret;
 }
diff --git a/fs/btrfs/props.h b/fs/btrfs/props.h
index b1a6b233b774..72bca072f9ba 100644
--- a/fs/btrfs/props.h
+++ b/fs/btrfs/props.h
@@ -10,8 +10,8 @@
 
 void __init btrfs_props_init(void);
 
-int btrfs_set_prop_trans(struct inode *inode, const char *name,
-			 const char *value, size_t value_len, int flags);
+int btrfs_set_prop(struct inode *inode, const char *name,
+		   const char *value, size_t value_len, int flags);
 
 int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path);
 
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index 58579a4d2f22..abc150a56f8b 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -371,7 +371,7 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
 					size_t size, int flags)
 {
 	name = xattr_full_name(handler, name);
-	return btrfs_set_prop_trans(inode, name, value, size, flags);
+	return btrfs_set_prop(inode, name, value, size, flags);
 }
 
 static const struct xattr_handler btrfs_security_xattr_handler = {
-- 
1.8.3.1


  parent reply	other threads:[~2019-04-02 10:08 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-02 10:07 [PATCH 0/4 RESEND] btrfs: fix property bugs Anand Jain
2019-04-02 10:07 ` [PATCH 1/4 RESEND] btrfs: fix zstd compression parameter Anand Jain
2019-04-02 22:09   ` David Sterba
2019-04-02 10:07 ` [PATCH] fstests: btrfs/048: amend property validation cases Anand Jain
2019-04-02 12:51   ` Nikolay Borisov
2019-04-03  0:32     ` Anand Jain
2019-04-02 10:07 ` [PATCH 2/4 RESEND] btrfs: fix vanished compression property after failed set Anand Jain
2019-04-02 13:00   ` Nikolay Borisov
2019-04-02 22:14   ` David Sterba
2019-04-02 10:07 ` [PATCH 3/4 RESEND] btrfs: open code btrfs_set_prop in inherit_prop Anand Jain
2019-04-02 13:35   ` Nikolay Borisov
2019-04-02 21:41     ` David Sterba
2019-04-02 23:24     ` David Sterba
2019-04-03  0:42       ` Anand Jain
2019-04-02 21:41   ` David Sterba
2019-04-02 10:07 ` Anand Jain [this message]
2019-04-02 13:45   ` [PATCH 4/4 RESEND] btrfs: fix property validate fail should not increment generation Nikolay Borisov
2019-04-02 21:13     ` David Sterba
2019-04-02 22:04   ` David Sterba
2019-04-02 23:03     ` Anand Jain

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=20190402100742.8355-6-anand.jain@oracle.com \
    --to=anand.jain@oracle.com \
    --cc=linux-btrfs@vger.kernel.org \
    /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.