Skip to contentSkip to conversation

Support for 'pending changes'

GIT PULL In review David Sterba 3 participants 11 messages Nov 14, 2014 – Jan 20, 2015 Btrfs file system

lore
Share & tools
lore
#0 lore raw

There are some actions that modify global filesystem state but cannot be performed at the time of request, but rather later at the transaction commit time when the filesystem is in a known state.

The change can be requested from any context and is permanent after sync. This changes the semantics for the sysfs files that modify label or feature bits, but I think this does not break existing applications.

You can pull the series from

git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git dev/pending-changes

David Sterba (6):
btrfs: add support for processing pending changes
btrfs: do commit in sync_fs if there are pending changes
btrfs: switch inode_cache option handling to pending changes
btrfs: introduce pending action: commit
btrfs: move commit out of sysfs when changing features
btrfs: move commit out of sysfs when changing label

 fs/btrfs/ctree.h       | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/btrfs/disk-io.c     |  8 +++++---
 fs/btrfs/inode-map.c   |  2 +-
 fs/btrfs/super.c       | 18 +++++++++++++-----
 fs/btrfs/sysfs.c       | 34 +++++++++++++---------------------
 fs/btrfs/transaction.c | 38 ++++++++++++++++++++++++++++++++------
 fs/btrfs/transaction.h |  2 ++
 7 files changed, 115 insertions(+), 37 deletions(-)
Signature · 1 line
1.8.4.5
#1 lore raw

PATCH 1/6 btrfs: add support for processing pending changes

There are some actions that modify global filesystem state but cannot be performed at the time of request, but later at the transaction commit time when the filesystem is in a known state.

For example enabling new incompat features on-the-fly or issuing transaction commit from unsafe contexts (sysfs handlers).

---
 fs/btrfs/ctree.h       | 45 +++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/disk-io.c     |  6 ++++++
 fs/btrfs/transaction.c | 16 ++++++++++++++++
 fs/btrfs/transaction.h |  2 ++
 4 files changed, 69 insertions(+)
fs/btrfs/ctree.h +45 -0
index fe69edda11fb..f30b061ef77d 100644
@@ -1402,6 +1402,11 @@ struct btrfs_fs_info {
 	 */
 	u64 last_trans_log_full_commit;
 	unsigned long mount_opt;
+	/*
+	 * Track requests for actions that need to be done during transaction
+	 * commit (like for some mount options).
+	 */
+	unsigned long pending_changes;
 	unsigned long compress_type:4;
 	int commit_interval;
 	/*
@@ -2103,6 +2108,7 @@ struct btrfs_ioctl_defrag_range_args {
 #define btrfs_raw_test_opt(o, opt)	((o) & BTRFS_MOUNT_##opt)
 #define btrfs_test_opt(root, opt)	((root)->fs_info->mount_opt & \
 					 BTRFS_MOUNT_##opt)
+
 #define btrfs_set_and_info(root, opt, fmt, args...)			\
 {									\
 	if (!btrfs_test_opt(root, opt))					\
@@ -2118,6 +2124,45 @@ struct btrfs_ioctl_defrag_range_args {
 }
 
 /*
+ * Requests for changes that need to be done during transaction commit.
+ *
+ * Internal mount options that are used for special handling of the real
+ * mount options (eg. cannot be set during remount and have to be set during
+ * transaction commit)
+ */
+
+#define btrfs_test_pending(info, opt)	\
+	test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
+#define btrfs_set_pending(info, opt)	\
+	set_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
+#define btrfs_clear_pending(info, opt)	\
+	clear_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
+
+/*
+ * Helpers for setting pending mount option changes.
+ *
+ * Expects corresponding macros
+ * BTRFS_PENDING_SET_ and CLEAR_ + short mount option name
+ */
+#define btrfs_set_pending_and_info(info, opt, fmt, args...)            \
+do {                                                                   \
+       if (!btrfs_raw_test_opt((info)->mount_opt, opt)) {              \
+               btrfs_info((info), fmt, ##args);                        \
+               btrfs_set_pending((info), SET_##opt);                   \
+               btrfs_clear_pending((info), CLEAR_##opt);               \
+       }                                                               \
+} while(0)
+
+#define btrfs_clear_pending_and_info(info, opt, fmt, args...)          \
+do {                                                                   \
+       if (btrfs_raw_test_opt((info)->mount_opt, opt)) {               \
+               btrfs_info((info), fmt, ##args);                        \
+               btrfs_set_pending((info), CLEAR_##opt);                 \
+               btrfs_clear_pending((info), SET_##opt);                 \
+       }                                                               \
+} while(0)
+
+/*
  * Inode flags
  */
 #define BTRFS_INODE_NODATASUM		(1 << 0)
fs/btrfs/disk-io.c +6 -0
index 1bf9f897065d..fd80c0d98421 100644
@@ -2834,6 +2834,12 @@ retry_root_backup:
 	if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE))
 		btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE);
 
+	/*
+	 * Mount does not set all options immediatelly, we can do it now and do
+	 * not have to wait for transaction commit
+	 */
+	btrfs_apply_pending_changes(fs_info);
+
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
 	if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
 		ret = btrfsic_mount(tree_root, fs_devices,
fs/btrfs/transaction.c +16 -0
index dcaae3616728..7a4024a55e5c 100644
@@ -1850,6 +1850,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 	else
 		btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
 
+	btrfs_apply_pending_changes(root->fs_info);
+
 	/* commit_fs_roots gets rid of all the tree log roots, it is now
 	 * safe to free the root of tree log roots
 	 */
@@ -2019,3 +2021,17 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
 
 	return (ret < 0) ? 0 : 1;
 }
+
+void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
+{
+	unsigned long prev;
+	unsigned long bit;
+
+	prev = cmpxchg(&fs_info->pending_changes, 0, 0);
+	if (!prev)
+		return;
+
+	if (prev)
+		btrfs_warn(fs_info,
+			"unknown pending changes left 0x%lx, ignoring", prev);
+}
fs/btrfs/transaction.h +2 -0
index d8f40e1a5d2d..75ebcfce9d57 100644
@@ -170,4 +170,6 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
 int btrfs_transaction_blocked(struct btrfs_fs_info *info);
 int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
 void btrfs_put_transaction(struct btrfs_transaction *transaction);
+void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info);
+
 #endif
Signature · 1 line
1.8.4.5
#2 lore raw

Re: [PATCH 1/6] btrfs: add support for processing pending changes

-------- Original Message --------
Subject: [PATCH 1/6] btrfs: add support for processing pending changes
From: David Sterba <[email protected]>
To: <[email protected]>
Date: 2014年11月14日 18:33

Quoted 116 lines

There are some actions that modify global filesystem state but cannot be performed at the time of request, but later at the transaction commit time when the filesystem is in a known state.

For example enabling new incompat features on-the-fly or issuing transaction commit from unsafe contexts (sysfs handlers).

---
  fs/btrfs/ctree.h       | 45 +++++++++++++++++++++++++++++++++++++++++++++
  fs/btrfs/disk-io.c     |  6 ++++++
  fs/btrfs/transaction.c | 16 ++++++++++++++++
  fs/btrfs/transaction.h |  2 ++
  4 files changed, 69 insertions(+)
fs/btrfs/ctree.h +45 -0
index fe69edda11fb..f30b061ef77d 100644
@@ -1402,6 +1402,11 @@ struct btrfs_fs_info {
  	 */
  	u64 last_trans_log_full_commit;
  	unsigned long mount_opt;
+	/*
+	 * Track requests for actions that need to be done during transaction
+	 * commit (like for some mount options).
+	 */
+	unsigned long pending_changes;
  	unsigned long compress_type:4;
  	int commit_interval;
  	/*
@@ -2103,6 +2108,7 @@ struct btrfs_ioctl_defrag_range_args {
  #define btrfs_raw_test_opt(o, opt)	((o) & BTRFS_MOUNT_##opt)
  #define btrfs_test_opt(root, opt)	((root)->fs_info->mount_opt & \
  					 BTRFS_MOUNT_##opt)
+
  #define btrfs_set_and_info(root, opt, fmt, args...)			\
  {									\
  	if (!btrfs_test_opt(root, opt))					\
@@ -2118,6 +2124,45 @@ struct btrfs_ioctl_defrag_range_args {
  }
 
  /*
+ * Requests for changes that need to be done during transaction commit.
+ *
+ * Internal mount options that are used for special handling of the real
+ * mount options (eg. cannot be set during remount and have to be set during
+ * transaction commit)
+ */
+
+#define btrfs_test_pending(info, opt)	\
+	test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
+#define btrfs_set_pending(info, opt)	\
+	set_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
+#define btrfs_clear_pending(info, opt)	\
+	clear_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
+
+/*
+ * Helpers for setting pending mount option changes.
+ *
+ * Expects corresponding macros
+ * BTRFS_PENDING_SET_ and CLEAR_ + short mount option name
+ */
+#define btrfs_set_pending_and_info(info, opt, fmt, args...)            \
+do {                                                                   \
+       if (!btrfs_raw_test_opt((info)->mount_opt, opt)) {              \
+               btrfs_info((info), fmt, ##args);                        \
+               btrfs_set_pending((info), SET_##opt);                   \
+               btrfs_clear_pending((info), CLEAR_##opt);               \
+       }                                                               \
+} while(0)
+
+#define btrfs_clear_pending_and_info(info, opt, fmt, args...)          \
+do {                                                                   \
+       if (btrfs_raw_test_opt((info)->mount_opt, opt)) {               \
+               btrfs_info((info), fmt, ##args);                        \
+               btrfs_set_pending((info), CLEAR_##opt);                 \
+               btrfs_clear_pending((info), SET_##opt);                 \
+       }                                                               \
+} while(0)
+
+/*
   * Inode flags
   */
  #define BTRFS_INODE_NODATASUM		(1 << 0)
fs/btrfs/disk-io.c +6 -0
index 1bf9f897065d..fd80c0d98421 100644
@@ -2834,6 +2834,12 @@ retry_root_backup:
  	if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE))
  		btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE);
 
+	/*
+	 * Mount does not set all options immediatelly, we can do it now and do
+	 * not have to wait for transaction commit
+	 */
+	btrfs_apply_pending_changes(fs_info);
+
  #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
  	if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
  		ret = btrfsic_mount(tree_root, fs_devices,
fs/btrfs/transaction.c +2 -0
index dcaae3616728..7a4024a55e5c 100644
@@ -1850,6 +1850,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
  	else
  		btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
 
+	btrfs_apply_pending_changes(root->fs_info);
+
  	/* commit_fs_roots gets rid of all the tree log roots, it is now
  	 * safe to free the root of tree log roots
  	 */

fs/btrfs/transaction.c int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) · line 2030

Quoted 10 lines
fs/btrfs/transaction.c +7 -0
@@ -2019,3 +2021,17 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
 
  	return (ret < 0) ? 0 : 1;
  }
+
+void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
+{
+	unsigned long prev;
+	unsigned long bit;
+
+	prev = cmpxchg(&fs_info->pending_changes, 0, 0);

Another HUGE problem here.
cmpxchg will only change the pending_changes to 0 if it's already 0. If it not 0, it will not change pending_changes to 0.

So pending_changes will always be non-zero if set_pending....

Thanks,
Qu

Quoted 18 lines
fs/btrfs/transaction.c +7 -0
+	if (!prev)
+		return;
+
+	if (prev)
+		btrfs_warn(fs_info,
+			"unknown pending changes left 0x%lx, ignoring", prev);
+}
fs/btrfs/transaction.h +2 -0
index d8f40e1a5d2d..75ebcfce9d57 100644
@@ -170,4 +170,6 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
  int btrfs_transaction_blocked(struct btrfs_fs_info *info);
  int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
  void btrfs_put_transaction(struct btrfs_transaction *transaction);
+void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info);
+
  #endif
#3 lore raw

PATCH 2/6 btrfs: do commit in sync_fs if there are pending changes

In reply to David Sterba

If a pending change is requested, it's not processed unless there is a transaction commit about to happen, not even after sync or SYNC_FS ioctl. For example a remount that toggles the inode_cache option will not take effect after sync on a quiescent filesystem.

---
 fs/btrfs/super.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
fs/btrfs/super.c +11 -3
index 54bd91ece35b..1da16d59e115 100644
@@ -993,9 +993,17 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
 	trans = btrfs_attach_transaction_barrier(root);
 	if (IS_ERR(trans)) {
 		/* no transaction, don't bother */
-		if (PTR_ERR(trans) == -ENOENT)
-			return 0;
-		return PTR_ERR(trans);
+		if (PTR_ERR(trans) == -ENOENT) {
+			/*
+			 * Exit unless we have some pending changes
+			 * that need to go through commit
+			 */
+			if (fs_info->pending_changes == 0)
+				return 0;
+			trans = btrfs_start_transaction(root, 0);
+		} else {
+			return PTR_ERR(trans);
+		}
 	}
 	return btrfs_commit_transaction(trans, root);
 }
Signature · 1 line
1.8.4.5
#4 lore raw

Re: [PATCH 2/6] btrfs: do commit in sync_fs if there are pending changes

Quoted 19 lines · David Sterba

If a pending change is requested, it's not processed unless there is a transaction commit about to happen, not even after sync or SYNC_FS ioctl. For example a remount that toggles the inode_cache option will not take effect after sync on a quiescent filesystem.

---
 fs/btrfs/super.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
fs/btrfs/super.c +0 -1
index 54bd91ece35b..1da16d59e115 100644
@@ -993,9 +993,17 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        trans = btrfs_attach_transaction_barrier(root);
        if (IS_ERR(trans)) {
                /* no transaction, don't bother */
-               if (PTR_ERR(trans) == -ENOENT)

fs/btrfs/super.c int btrfs_sync_fs(struct super_block *sb, int wait) · line 1003

Quoted 10 lines
fs/btrfs/super.c +8 -2
-                       return 0;
-               return PTR_ERR(trans);
+               if (PTR_ERR(trans) == -ENOENT) {
+                       /*
+                        * Exit unless we have some pending changes
+                        * that need to go through commit
+                        */
+                       if (fs_info->pending_changes == 0)
+                               return 0;
+                       trans = btrfs_start_transaction(root, 0);

Missing check for IS_ERR(trans)

The rest looks good.
Thanks

Quoted 13 lines
fs/btrfs/super.c +3 -1
+               } else {
+                       return PTR_ERR(trans);
+               }
        }
        return btrfs_commit_transaction(trans, root);
 }
--

1.8.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 5 lines
Filipe David Manana,

"Reasonable men adapt themselves to the world.
 Unreasonable men adapt the world to themselves.
 That's why all progress depends on unreasonable men."
#5 lore raw

PATCH v2 2/6 btrfs: do commit in sync_fs if there are pending changes

In reply to David Sterba

If a pending change is requested, it's not processed unless there is a transaction commit about to happen, not even after sync or SYNC_FS ioctl. For example a remount that toggles the inode_cache option will not take effect after sync on a quiescent filesystem.

---

v2: catch error from btrfs_start_transaction

 fs/btrfs/super.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
fs/btrfs/super.c +11 -3
index 54bd91ece35b..0cf589402d8d 100644
@@ -993,9 +993,17 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
 	trans = btrfs_attach_transaction_barrier(root);
 	if (IS_ERR(trans)) {
 		/* no transaction, don't bother */
-		if (PTR_ERR(trans) == -ENOENT)
-			return 0;
-		return PTR_ERR(trans);
+		if (PTR_ERR(trans) == -ENOENT) {
+			/*
+			 * Exit unless we have some pending changes
+			 * that need to go through commit
+			 */
+			if (fs_info->pending_changes == 0)
+				return 0;
+			trans = btrfs_start_transaction(root, 0);
+		}
+		if (IS_ERR(trans))
+			return PTR_ERR(trans);
 	}
 	return btrfs_commit_transaction(trans, root);
 }
Signature · 1 line
2.1.3
#6 lore raw

Re: [PATCH 2/6 v2] btrfs: do commit in sync_fs if there are pending changes

Quoted 9 lines · David Sterba

If a pending change is requested, it's not processed unless there is a transaction commit about to happen, not even after sync or SYNC_FS ioctl. For example a remount that toggles the inode_cache option will not take effect after sync on a quiescent filesystem.

---

v2: catch error from btrfs_start_transaction

V2 didn't make it to 3.19:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6b5fe46dfa52441f49c7432b1c1b1cb767834708

Quoted 36 lines
 fs/btrfs/super.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
fs/btrfs/super.c +11 -4
index 54bd91ece35b..0cf589402d8d 100644
@@ -993,9 +993,17 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        trans = btrfs_attach_transaction_barrier(root);
        if (IS_ERR(trans)) {
                /* no transaction, don't bother */
-               if (PTR_ERR(trans) == -ENOENT)
-                       return 0;
-               return PTR_ERR(trans);
+               if (PTR_ERR(trans) == -ENOENT) {
+                       /*
+                        * Exit unless we have some pending changes
+                        * that need to go through commit
+                        */
+                       if (fs_info->pending_changes == 0)
+                               return 0;
+                       trans = btrfs_start_transaction(root, 0);
+               }
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
        }
        return btrfs_commit_transaction(trans, root);
 }
--

2.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 5 lines
Filipe David Manana,

"Reasonable men adapt themselves to the world.
 Unreasonable men adapt the world to themselves.
 That's why all progress depends on unreasonable men."
#7 lore raw

PATCH 3/6 btrfs: switch inode_cache option handling to pending changes

In reply to David Sterba

The pending mount option(s) now share namespace and bits with the normal options, and the existing one for (inode_cache) is unset unconditionally at each transaction commit.

Introduce a separate namespace for pending changes and enhance the descriptions of the intended change to use separate bits for each action.

---
 fs/btrfs/ctree.h       |  4 +++-
 fs/btrfs/disk-io.c     |  4 ----
 fs/btrfs/inode-map.c   |  2 +-
 fs/btrfs/super.c       |  4 ++--
 fs/btrfs/transaction.c | 19 ++++++++++++-------
 5 files changed, 18 insertions(+), 15 deletions(-)
fs/btrfs/ctree.h +3 -1
index f30b061ef77d..1c9157e4ab0c 100644
@@ -2098,7 +2098,6 @@ struct btrfs_ioctl_defrag_range_args {
 #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
 #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR	(1 << 22)
 #define BTRFS_MOUNT_RESCAN_UUID_TREE	(1 << 23)
-#define	BTRFS_MOUNT_CHANGE_INODE_CACHE	(1 << 24)
 
 #define BTRFS_DEFAULT_COMMIT_INTERVAL	(30)
 #define BTRFS_DEFAULT_MAX_INLINE	(8192)
@@ -2131,6 +2130,9 @@ struct btrfs_ioctl_defrag_range_args {
  * transaction commit)
  */
 
+#define BTRFS_PENDING_SET_INODE_MAP_CACHE	(0)
+#define BTRFS_PENDING_CLEAR_INODE_MAP_CACHE	(1)
+
 #define btrfs_test_pending(info, opt)	\
 	test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
 #define btrfs_set_pending(info, opt)	\
fs/btrfs/disk-io.c +0 -4
index fd80c0d98421..6b406e3f3abe 100644
@@ -2830,10 +2830,6 @@ retry_root_backup:
 		btrfs_set_opt(fs_info->mount_opt, SSD);
 	}
 
-	/* Set the real inode map cache flag */
-	if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE))
-		btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE);
-
 	/*
 	 * Mount does not set all options immediatelly, we can do it now and do
 	 * not have to wait for transaction commit
fs/btrfs/inode-map.c +1 -1
index 83d646bd2e4b..4ebd5ebb1ea1 100644
@@ -178,7 +178,7 @@ static void start_caching(struct btrfs_root *root)
 			  root->root_key.objectid);
 	if (IS_ERR(tsk)) {
 		btrfs_warn(root->fs_info, "failed to start inode caching task");
-		btrfs_clear_and_info(root, CHANGE_INODE_CACHE,
+		btrfs_clear_pending_and_info(root->fs_info, INODE_MAP_CACHE,
 				"disabling inode map caching");
 	}
 }
fs/btrfs/super.c +2 -2
index 1da16d59e115..65c75d9e9750 100644
@@ -642,11 +642,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
 					     "disabling disk space caching");
 			break;
 		case Opt_inode_cache:
-			btrfs_set_and_info(root, CHANGE_INODE_CACHE,
+			btrfs_set_pending_and_info(info, INODE_MAP_CACHE,
 					   "enabling inode map caching");
 			break;
 		case Opt_noinode_cache:
-			btrfs_clear_and_info(root, CHANGE_INODE_CACHE,
+			btrfs_clear_pending_and_info(info, INODE_MAP_CACHE,
 					     "disabling inode map caching");
 			break;
 		case Opt_clear_cache:
fs/btrfs/transaction.c +12 -7
index 7a4024a55e5c..703238ed7337 100644
@@ -1842,14 +1842,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 	}
 
 	/*
-	 * Since the transaction is done, we should set the inode map cache flag
-	 * before any other comming transaction.
+	 * Since the transaction is done, we can apply the pending changes
+	 * before the next transaction.
 	 */
-	if (btrfs_test_opt(root, CHANGE_INODE_CACHE))
-		btrfs_set_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
-	else
-		btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
-
 	btrfs_apply_pending_changes(root->fs_info);
 
 	/* commit_fs_roots gets rid of all the tree log roots, it is now
@@ -2031,6 +2026,16 @@ void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
 	if (!prev)
 		return;
 
+	bit = 1 << BTRFS_PENDING_SET_INODE_MAP_CACHE;
+	if (prev & bit)
+		btrfs_set_opt(fs_info->mount_opt, INODE_MAP_CACHE);
+	prev &= ~bit;
+
+	bit = 1 << BTRFS_PENDING_CLEAR_INODE_MAP_CACHE;
+	if (prev & bit)
+		btrfs_clear_opt(fs_info->mount_opt, INODE_MAP_CACHE);
+	prev &= ~bit;
+
 	if (prev)
 		btrfs_warn(fs_info,
 			"unknown pending changes left 0x%lx, ignoring", prev);
Signature · 1 line
1.8.4.5
#8 lore raw

PATCH 4/6 btrfs: introduce pending action: commit

In reply to David Sterba

In some contexts, like in sysfs handlers, we don't want to trigger a transaction commit. It's a heavy operation, we don't know what external locks may be taken. Instead, make it possible to finish the operation through sync syscall or SYNC_FS ioctl.

---
 fs/btrfs/ctree.h       | 1 +
 fs/btrfs/transaction.c | 5 +++++
 2 files changed, 6 insertions(+)
fs/btrfs/ctree.h +1 -0
index 1c9157e4ab0c..817fc19b8159 100644
@@ -2132,6 +2132,7 @@ struct btrfs_ioctl_defrag_range_args {
 
 #define BTRFS_PENDING_SET_INODE_MAP_CACHE	(0)
 #define BTRFS_PENDING_CLEAR_INODE_MAP_CACHE	(1)
+#define BTRFS_PENDING_COMMIT			(2)
 
 #define btrfs_test_pending(info, opt)	\
 	test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
fs/btrfs/transaction.c +5 -0
index 703238ed7337..9d8e2b8d12b4 100644
@@ -2036,6 +2036,11 @@ void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
 		btrfs_clear_opt(fs_info->mount_opt, INODE_MAP_CACHE);
 	prev &= ~bit;
 
+	bit = 1 << BTRFS_PENDING_COMMIT;
+	if (prev & bit)
+		btrfs_debug(fs_info, "pending commit done");
+	prev &= ~bit;
+
 	if (prev)
 		btrfs_warn(fs_info,
 			"unknown pending changes left 0x%lx, ignoring", prev);
Signature · 1 line
1.8.4.5
#9 lore raw

PATCH 5/6 btrfs: move commit out of sysfs when changing features

In reply to David Sterba
---
 fs/btrfs/sysfs.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)
fs/btrfs/sysfs.c +5 -8
index b2e7bb4393f6..226f7261533a 100644
@@ -111,7 +111,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
 {
 	struct btrfs_fs_info *fs_info;
 	struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
-	struct btrfs_trans_handle *trans;
 	u64 features, set, clear;
 	unsigned long val;
 	int ret;
@@ -153,10 +152,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
 	btrfs_info(fs_info, "%s %s feature flag",
 		   val ? "Setting" : "Clearing", fa->kobj_attr.attr.name);
 
-	trans = btrfs_start_transaction(fs_info->fs_root, 0);
-	if (IS_ERR(trans))
-		return PTR_ERR(trans);
-
 	spin_lock(&fs_info->super_lock);
 	features = get_features(fs_info, fa->feature_set);
 	if (val)
@@ -166,9 +161,11 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
 	set_features(fs_info, fa->feature_set, features);
 	spin_unlock(&fs_info->super_lock);
 
-	ret = btrfs_commit_transaction(trans, fs_info->fs_root);
-	if (ret)
-		return ret;
+	/*
+	 * We don't want to do full transaction commit from inside sysfs
+	 */
+	btrfs_set_pending(fs_info, COMMIT);
+	wake_up_process(fs_info->transaction_kthread);
 
 	return count;
 }
Signature · 1 line
1.8.4.5
#10 lore raw

PATCH 6/6 btrfs: move commit out of sysfs when changing label

In reply to David Sterba
---
 fs/btrfs/sysfs.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)
fs/btrfs/sysfs.c +8 -13
index 226f7261533a..92db3f648df4 100644
@@ -369,9 +369,6 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
 				 const char *buf, size_t len)
 {
 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
-	struct btrfs_trans_handle *trans;
-	struct btrfs_root *root = fs_info->fs_root;
-	int ret;
 	size_t p_len;
 
 	if (fs_info->sb->s_flags & MS_RDONLY)
@@ -386,20 +383,18 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
 	if (p_len >= BTRFS_LABEL_SIZE)
 		return -EINVAL;
 
-	trans = btrfs_start_transaction(root, 0);
-	if (IS_ERR(trans))
-		return PTR_ERR(trans);
-
-	spin_lock(&root->fs_info->super_lock);
+	spin_lock(&fs_info->super_lock);
 	memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE);
 	memcpy(fs_info->super_copy->label, buf, p_len);
-	spin_unlock(&root->fs_info->super_lock);
-	ret = btrfs_commit_transaction(trans, root);
+	spin_unlock(&fs_info->super_lock);
 
-	if (!ret)
-		return len;
+	/*
+	 * We don't want to do full transaction commit from inside sysfs
+	 */
+	btrfs_set_pending(fs_info, COMMIT);
+	wake_up_process(fs_info->transaction_kthread);
 
-	return ret;
+	return len;
 }
 BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store);
 
Signature · 1 line
1.8.4.5