=====================
#!/bin/bash

BTRFS_ROOT=/

states=(
  compress=zlib,datacow,datasum
  compress=lzo,datacow,datasum
  compress-force=zlib,datacow,datasum
  compress-force=lzo,datacow,datasum
  compress=no,nodatacow,nodatasum
  compress=no,datacow,nodatasum
  compress=no,datacow,datasum
)

options=(
  compress
  compress=zlib
  compress=lzo
  compress=no
  compress=badopt
  compress-force
  compress-force=zlib
  compress-force=lzo
  compress-force=no
  compress-force=badopt
  nodatacow
  datacow
  nodatasum
  datasum
)

for s in ${states[@]}; do
  for o in ${options[@]}; do
    # set initial state
    echo initial: mount -o remount,$s
    mount -o remount,$s ${BTRFS_ROOT}
    # mount with each option
    echo mount -o remount,$o
    dmesg -C
    mount -o remount,$o ${BTRFS_ROOT}
    echo dmesg:
    dmesg -t | perl -ne 'if(/^BTRFS info \(device .+?\): (.+)$/){print "\t$1\n"}'
    echo -n 'mount options: '
    grep -v rootfs /proc/mounts | \
      awk "{if(\$2==\"${BTRFS_ROOT}\"){print \$4}}" | \
      perl -ne '@a=split(/,/); for(@a){print "$_ " if(/^compress(-force)?=|nodata(cow|sum)$/)}'
    echo
    echo
  done
done
=====================

Signed-off-by: Naohiro Aota <naota@elisp.net>
Signed-off-by: Satoru Takeuchi <takeuchi_satoru@jp.fujitsu.com>
---
 fs/btrfs/super.c | 57 +++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 17 deletions(-)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 03131c5..83433e15 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -401,6 +401,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
 	char *compress_type;
 	bool compress_force = false;
 	bool compress = false;
+	unsigned long old_compress_type;
 
 	cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy);
 	if (cache_gen)
@@ -486,40 +487,62 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
 		case Opt_compress:
 		case Opt_compress_type:
 			compress = true;
+			old_compress_type = info->compress_type;
 			if (token == Opt_compress ||
 			    token == Opt_compress_force ||
 			    strcmp(args[0].from, "zlib") == 0) {
 				compress_type = "zlib";
 				info->compress_type = BTRFS_COMPRESS_ZLIB;
-				btrfs_set_opt(info->mount_opt, COMPRESS);
-				btrfs_clear_opt(info->mount_opt, NODATACOW);
-				btrfs_clear_opt(info->mount_opt, NODATASUM);
 			} else if (strcmp(args[0].from, "lzo") == 0) {
 				compress_type = "lzo";
 				info->compress_type = BTRFS_COMPRESS_LZO;
-				btrfs_set_opt(info->mount_opt, COMPRESS);
-				btrfs_clear_opt(info->mount_opt, NODATACOW);
-				btrfs_clear_opt(info->mount_opt, NODATASUM);
 				btrfs_set_fs_incompat(info, COMPRESS_LZO);
 			} else if (strncmp(args[0].from, "no", 2) == 0) {
 				compress_type = "no";
-				btrfs_clear_opt(info->mount_opt, COMPRESS);
-				btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
-				compress_force = false;
+				compress = compress_force = false;
 			} else {
 				ret = -EINVAL;
 				goto out;
 			}
 
-			if (compress_force) {
-				btrfs_set_and_info(root, FORCE_COMPRESS,
-						   "force %s compression",
-						   compress_type);
-			} else if (compress) {
-				if (!btrfs_test_opt(root, COMPRESS))
+			if (compress_force || compress) {
+				const char *method = "", *setting = "";
+
+				if ((info->compress_type != old_compress_type) ||
+				    (compress_force &&
+				     !btrfs_test_opt(root, FORCE_COMPRESS)) ||
+				    (!compress_force &&
+				     btrfs_test_opt(root, FORCE_COMPRESS)) ||
+				    (compress && !btrfs_test_opt(root, COMPRESS))) {
+					method = compress_force?"force":"use";
+				}
+
+				if (btrfs_test_opt(root, NODATACOW))
+					setting = ", setting datacow and datasum";
+				else if (btrfs_test_opt(root, NODATASUM))
+					setting = ", setting datasum";
+
+				if (strcmp(method, "") != 0) {
 					btrfs_info(root->fs_info,
-						   "btrfs: use %s compression",
-						   compress_type);
+						   "%s %s compression%s",
+						   method, compress_type,
+						   setting);
+				}
+				if (compress_force) {
+					btrfs_set_opt(info->mount_opt,
+						      FORCE_COMPRESS);
+				} else {
+					btrfs_clear_opt(info->mount_opt,
+							FORCE_COMPRESS);
+				}
+				btrfs_set_opt(info->mount_opt, COMPRESS);
+				btrfs_clear_opt(info->mount_opt, NODATACOW);
+				btrfs_clear_opt(info->mount_opt, NODATASUM);
+			} else {
+				btrfs_clear_and_info(root, COMPRESS,
+						     "use no compression");
+				btrfs_clear_opt(info->mount_opt,
+						FORCE_COMPRESS);
 			}
 			break;
 		case Opt_ssd:
