All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] btrfs feature testing + props fix
@ 2016-06-27 20:14 jeffm
  2016-06-27 20:14 ` [PATCH v2 1/4] btrfs/048: extend _filter_btrfs_prop_error to handle additional errors jeffm
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: jeffm @ 2016-06-27 20:14 UTC (permalink / raw)
  To: fstests, linux-btrfs; +Cc: Eryu Guan

From: Jeff Mahoney <jeffm@suse.com>

Hi all -

Thanks, Eryu, for the review.  The btrfs feature testing changes were a
patchet I wrote three years ago, and it looks like significant cleanup
has happened in the xfstests since then.  I'm sorry for the level of the
review you had to do for them, but do appreciate that you did.

This version should fix the outstanding issues, including some issues
with the tests themselves, where e.g. the 32MB reserved size was file
system-size (and implementation) dependent.  Most notably, since these
tests share some common functionality that ultimately hit ~250 lines, I
chose to create a new common/btrfs library.  Other than that, I tried to
meet the level of consistency you were looking for with just printing
errors instead of failing, not depending on error codes, etc.

Thanks,

-Jeff

---

Jeff Mahoney (4):
  btrfs/048: extend _filter_btrfs_prop_error to handle additional errors
  btrfs/124: test global metadata reservation reporting
  btrfs/125: test sysfs exports of allocation and device membership info
  btrfs/126,127,128: test feature ioctl and sysfs interfaces

 .gitignore               |   1 +
 common/btrfs             | 253 +++++++++++++++++++++++++++++++++++++++++++++++
 common/config            |   7 +-
 common/filter.btrfs      |  10 +-
 src/Makefile             |   3 +-
 src/btrfs_ioctl_helper.c | 220 +++++++++++++++++++++++++++++++++++++++++
 tests/btrfs/048          |   6 +-
 tests/btrfs/048.out      |   4 +-
 tests/btrfs/124          |  84 ++++++++++++++++
 tests/btrfs/124.out      |   1 +
 tests/btrfs/125          | 177 +++++++++++++++++++++++++++++++++
 tests/btrfs/125.out      |   1 +
 tests/btrfs/126          | 244 +++++++++++++++++++++++++++++++++++++++++++++
 tests/btrfs/126.out      |   1 +
 tests/btrfs/127          | 166 +++++++++++++++++++++++++++++++
 tests/btrfs/127.out      |   1 +
 tests/btrfs/128          | 128 ++++++++++++++++++++++++
 tests/btrfs/128.out      |   1 +
 tests/btrfs/group        |   5 +
 19 files changed, 1302 insertions(+), 11 deletions(-)
 create mode 100644 common/btrfs
 create mode 100644 src/btrfs_ioctl_helper.c
 create mode 100755 tests/btrfs/124
 create mode 100644 tests/btrfs/124.out
 create mode 100755 tests/btrfs/125
 create mode 100644 tests/btrfs/125.out
 create mode 100755 tests/btrfs/126
 create mode 100644 tests/btrfs/126.out
 create mode 100755 tests/btrfs/127
 create mode 100644 tests/btrfs/127.out
 create mode 100755 tests/btrfs/128
 create mode 100644 tests/btrfs/128.out

-- 
1.8.5.6


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/4] btrfs/048: extend _filter_btrfs_prop_error to handle additional errors
  2016-06-27 20:14 [PATCH v2 0/4] btrfs feature testing + props fix jeffm
@ 2016-06-27 20:14 ` jeffm
  2016-06-29 13:48   ` Eryu Guan
  2016-06-27 20:14 ` [PATCH v2 2/4] btrfs/124: test global metadata reservation reporting jeffm
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: jeffm @ 2016-06-27 20:14 UTC (permalink / raw)
  To: fstests, linux-btrfs; +Cc: Eryu Guan

From: Jeff Mahoney <jeffm@suse.com>

btrfsprogs v4.5.3 changed the formatting of some error messages.  This
patch extends the filter for btrfs prop to handle those.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 common/filter.btrfs | 10 +++++++---
 tests/btrfs/048     |  6 ++++--
 tests/btrfs/048.out |  4 ++--
 3 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/common/filter.btrfs b/common/filter.btrfs
index 9970f4d..0cf7f0d 100644
--- a/common/filter.btrfs
+++ b/common/filter.btrfs
@@ -72,15 +72,19 @@ _filter_btrfs_compress_property()
 	sed -e "s/compression=\(lzo\|zlib\)/COMPRESSION=XXX/g"
 }
 
-# filter name of the property from the output, optionally verify against $1
+# filter error messages from btrfs prop, optionally verify against $1
 # recognized message(s):
 #  "object is not compatible with property: label"
+#  "invalid value for property:{, value}"
+#  "failed to {get,set} compression for $PATH[.:]: Invalid argument"
 _filter_btrfs_prop_error()
 {
 	if ! [ -z "$1" ]; then
-		sed -e "s/\(compatible with property\): $1/\1/"
+		sed -e "s#\(compatible with property\): $1#\1#" \
+		    -e "s#^\(.*failed to [sg]et compression for $1\)[:.] \(.*\)#\1: \2#"
 	else
-		sed -e "s/^\(.*compatible with property\).*/\1/"
+		sed -e "s#^\(.*compatible with property\).*#\1#" \
+		    -e "s#^\(.*invalid value for property\)[:.].*#\1#"
 	fi
 }
 
diff --git a/tests/btrfs/048 b/tests/btrfs/048
index 4a36303..0b907b0 100755
--- a/tests/btrfs/048
+++ b/tests/btrfs/048
@@ -79,7 +79,8 @@ echo -e "\nTesting subvolume ro property"
 _run_btrfs_util_prog subvolume create $SCRATCH_MNT/sv1
 $BTRFS_UTIL_PROG property get $SCRATCH_MNT/sv1 ro
 echo "***"
-$BTRFS_UTIL_PROG property set $SCRATCH_MNT/sv1 ro foo
+$BTRFS_UTIL_PROG property set $SCRATCH_MNT/sv1 ro foo 2>&1 |
+	_filter_btrfs_prop_error
 echo "***"
 $BTRFS_UTIL_PROG property set $SCRATCH_MNT/sv1 ro true
 echo "***"
@@ -99,7 +100,8 @@ $BTRFS_UTIL_PROG property get $SCRATCH_MNT/testdir/file1 compression
 $BTRFS_UTIL_PROG property get $SCRATCH_MNT/testdir/subdir1 compression
 echo "***"
 $BTRFS_UTIL_PROG property set $SCRATCH_MNT/testdir/file1 compression \
-	foo 2>&1 | _filter_scratch
+	foo 2>&1 | _filter_scratch |
+	_filter_btrfs_prop_error SCRATCH_MNT/testdir/file1
 echo "***"
 $BTRFS_UTIL_PROG property set $SCRATCH_MNT/testdir/file1 compression lzo
 $BTRFS_UTIL_PROG property get $SCRATCH_MNT/testdir/file1 compression
diff --git a/tests/btrfs/048.out b/tests/btrfs/048.out
index 0b20d0b..3e4e3d2 100644
--- a/tests/btrfs/048.out
+++ b/tests/btrfs/048.out
@@ -15,7 +15,7 @@ ERROR: object is not compatible with property
 Testing subvolume ro property
 ro=false
 ***
-ERROR: invalid value for property.
+ERROR: invalid value for property
 ***
 ***
 ro=true
@@ -27,7 +27,7 @@ ro=false
 
 Testing compression property
 ***
-ERROR: failed to set compression for SCRATCH_MNT/testdir/file1. Invalid argument
+ERROR: failed to set compression for SCRATCH_MNT/testdir/file1: Invalid argument
 ***
 compression=lzo
 compression=lzo
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/4] btrfs/124: test global metadata reservation reporting
  2016-06-27 20:14 [PATCH v2 0/4] btrfs feature testing + props fix jeffm
  2016-06-27 20:14 ` [PATCH v2 1/4] btrfs/048: extend _filter_btrfs_prop_error to handle additional errors jeffm
@ 2016-06-27 20:14 ` jeffm
  2016-06-30  4:07   ` Eryu Guan
  2016-06-27 20:14 ` [PATCH v2 3/4] btrfs/125: test sysfs exports of allocation and device membership info jeffm
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: jeffm @ 2016-06-27 20:14 UTC (permalink / raw)
  To: fstests, linux-btrfs; +Cc: Eryu Guan

From: Jeff Mahoney <jeffm@suse.com>

Btrfs can now report the size of the global metadata reservation
via ioctl and sysfs.

This test confirms that we get sane results on an empty file system.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 .gitignore               |   1 +
 common/btrfs             |  43 +++++++++++++++
 src/Makefile             |   3 +-
 src/btrfs_ioctl_helper.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/btrfs/124          |  84 ++++++++++++++++++++++++++++++
 tests/btrfs/124.out      |   1 +
 tests/btrfs/group        |   1 +
 7 files changed, 264 insertions(+), 1 deletion(-)
 create mode 100644 common/btrfs
 create mode 100644 src/btrfs_ioctl_helper.c
 create mode 100755 tests/btrfs/124
 create mode 100644 tests/btrfs/124.out

diff --git a/.gitignore b/.gitignore
index 28bd180..0e4f2a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@
 /src/append_reader
 /src/append_writer
 /src/bstat
+/src/btrfs_ioctl_helper
 /src/bulkstat_unlink_test
 /src/bulkstat_unlink_test_modified
 /src/dbtest
diff --git a/common/btrfs b/common/btrfs
new file mode 100644
index 0000000..b972b13
--- /dev/null
+++ b/common/btrfs
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Functions for testing btrfs
+
+_btrfs_get_fsid()
+{
+	local mnt=$1
+	if [ -z "$mnt" ]; then
+		mnt=$TEST_DIR
+	fi
+	$BTRFS_UTIL_PROG filesystem show $mnt|awk '/uuid:/ {print $NF}'
+}
+
+_btrfs_get_sysfs()
+{
+	local mnt=$1
+	local fsid=$(_btrfs_get_fsid $mnt)
+	echo "/sys/fs/btrfs/$fsid"
+}
+
+_require_btrfs_sysfs()
+{
+	local mnt=$1
+	if [ -z "$mnt" ]; then
+		mnt=$TEST_DIR
+	fi
+	if [ ! -d "$(_btrfs_get_sysfs $mnt)" ];then
+		_notrun "btrfs sysfs support not available."
+	fi
+}
+
+_require_btrfs_ioctl()
+{
+	local ioctl=$1
+	local mnt=$2
+	shift 2
+	if [ -z "$mnt" ]; then
+		mnt=$TEST_DIR
+	fi
+	out=$(src/btrfs_ioctl_helper $mnt $ioctl $@)
+	if [ "$out" = "Not implemented." ]; then
+		_notrun "btrfs ioctl $ioctl not implemented."
+	fi
+}
diff --git a/src/Makefile b/src/Makefile
index 1bf318b..c467475 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -20,7 +20,8 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
 	bulkstat_unlink_test_modified t_dir_offset t_futimens t_immutable \
 	stale_handle pwrite_mmap_blocked t_dir_offset2 seek_sanity_test \
 	seek_copy_test t_readdir_1 t_readdir_2 fsync-tester nsexec cloner \
-	renameat2 t_getcwd e4compact test-nextquota punch-alternating
+	renameat2 t_getcwd e4compact test-nextquota punch-alternating \
+	btrfs_ioctl_helper
 
 SUBDIRS =
 
diff --git a/src/btrfs_ioctl_helper.c b/src/btrfs_ioctl_helper.c
new file mode 100644
index 0000000..b6eb924
--- /dev/null
+++ b/src/btrfs_ioctl_helper.c
@@ -0,0 +1,132 @@
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#ifndef BTRFS_IOCTL_MAGIC
+#define BTRFS_IOCTL_MAGIC 0x94
+#endif
+
+#ifndef BTRFS_IOC_SPACE_INFO
+struct btrfs_ioctl_space_info {
+        uint64_t flags;
+        uint64_t total_bytes;
+        uint64_t used_bytes;
+};
+
+struct btrfs_ioctl_space_args {
+        uint64_t space_slots;
+        uint64_t total_spaces;
+        struct btrfs_ioctl_space_info spaces[0];
+};
+#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
+                                    struct btrfs_ioctl_space_args)
+#endif
+#ifndef BTRFS_SPACE_INFO_GLOBAL_RSV
+#define BTRFS_SPACE_INFO_GLOBAL_RSV    (1ULL << 49)
+#endif
+
+static int global_rsv_ioctl(int fd, int argc, char *argv[])
+{
+	struct btrfs_ioctl_space_args arg;
+	struct btrfs_ioctl_space_args *args;
+	int ret;
+	int i;
+	size_t size;
+
+	arg.space_slots = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, &arg);
+	if (ret)
+		return -errno;
+
+	size = sizeof(*args) + sizeof(args->spaces[0]) * arg.total_spaces;
+	args = malloc(size);
+	if (!args)
+		return -ENOMEM;
+
+	args->space_slots = arg.total_spaces;
+
+	ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, args);
+	if (ret)
+		return -errno;
+
+	for (i = 0; i < args->total_spaces; i++) {
+		if (args->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) {
+			unsigned long long reserved;
+			reserved = args->spaces[i].total_bytes;
+			printf("%llu\n", reserved);
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+#define IOCTL_TABLE_ENTRY(_ioctl_name, _handler) \
+	{ .name = #_ioctl_name, .ioctl_cmd = BTRFS_IOC_##_ioctl_name, \
+	  .handler = _handler, }
+
+struct ioctl_table_entry {
+	const char *name;
+	unsigned ioctl_cmd;
+	int (*handler)(int fd, int argc, char *argv[]);
+};
+
+static struct ioctl_table_entry ioctls[] = {
+	IOCTL_TABLE_ENTRY(SPACE_INFO, global_rsv_ioctl),
+};
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	int ret;
+	struct ioctl_table_entry *entry = NULL;
+	int i;
+
+	if (argc < 3) {
+		fprintf(stderr,
+			"usage: %s <fs mount point> <ioctl name> [args..]\n",
+			argv[0]);
+		return 1;
+	}
+
+	fd = open(argv[1], O_RDONLY|O_DIRECTORY);
+	if (fd < 0) {
+		perror(argv[1]);
+		return 1;
+	}
+
+	for (i = 0; i < (sizeof(ioctls)/sizeof(ioctls[0])); i++) {
+		if (strcmp(argv[2], ioctls[i].name) == 0) {
+			entry = &ioctls[i];
+			break;
+		}
+	}
+
+	if (!entry) {
+		fprintf(stderr, "ERROR: unknown ioctl %s\n", argv[2]);
+		close(fd);
+		return 1;
+	}
+
+	ret = entry->handler(fd, argc - 3, argv + 3);
+	if (ret == -ENOTTY) {
+		printf("Not implemented.\n");
+		close(fd);
+		return 0;
+	} else if (ret) {
+		fprintf(stderr, "ERROR: %s failed: %s\n",
+			entry->name, strerror(-ret));
+		close(fd);
+		return 1;
+	}
+
+	close(fd);
+	return 0;
+}
diff --git a/tests/btrfs/124 b/tests/btrfs/124
new file mode 100755
index 0000000..2ab9dfb
--- /dev/null
+++ b/tests/btrfs/124
@@ -0,0 +1,84 @@
+#!/bin/bash
+# FA QA Test No. 124
+#
+# Test global metadata reservation reporting
+#
+# 1) Create empty file system
+# 2) Call the BTRFS_IOC_GLOBAL_RSV ioctl
+# 3) Read the /sys/fs/btrfs/<fsid>/allocation/global_rsv_reserved file
+#    and confirm it's a number
+# 4) Compare the results between the two to confirm they match
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 SUSE, All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  12110-1301  USA
+#-----------------------------------------------------------------------
+
+seq=$(basename $0)
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=$(pwd)
+tmp=/tmp/$$
+status=1
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/btrfs
+. ./common/filter.btrfs
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+_supported_fs btrfs
+_supported_os Linux
+_require_test
+_require_btrfs_ioctl SPACE_INFO
+_require_btrfs_sysfs
+
+IOCTL="src/btrfs_ioctl_helper"
+
+SYSFS_PREFIX="$(_btrfs_get_sysfs)/allocation"
+[ -d "$SYSFS_PREFIX" ] || _notrun "sysfs directory not found"
+
+check_sysfs_output()
+{
+	reserved="$1"
+	method="$2"
+	if [ -n "$(echo $reserved | tr -d 0-9)" ]; then
+		echo "$method: numerical value expected (got $reserved)"
+	fi
+}
+
+ioctl_reserved="$($IOCTL $TEST_DIR SPACE_INFO)"
+
+reserved="$(cat $SYSFS_PREFIX/global_rsv_reserved)"
+check_sysfs_output "$reserved" "sysfs:reserved"
+if [ "$reserved" != "$ioctl_reserved" ]; then
+	echo "ioctl ($ioctl_reserved) != sysfs ($reserved)"
+fi
+size="$(cat $SYSFS_PREFIX/global_rsv_size)"
+check_sysfs_output "$size" "sysfs:size"
+
+# success, all done
+status=0
+exit
diff --git a/tests/btrfs/124.out b/tests/btrfs/124.out
new file mode 100644
index 0000000..0129e81
--- /dev/null
+++ b/tests/btrfs/124.out
@@ -0,0 +1 @@
+QA output created by 124
diff --git a/tests/btrfs/group b/tests/btrfs/group
index 5a26ed7..8b5050e 100644
--- a/tests/btrfs/group
+++ b/tests/btrfs/group
@@ -126,3 +126,4 @@
 121 auto quick snapshot qgroup
 122 auto quick snapshot qgroup
 123 auto quick qgroup
+124 auto quick metadata
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/4] btrfs/125: test sysfs exports of allocation and device membership info
  2016-06-27 20:14 [PATCH v2 0/4] btrfs feature testing + props fix jeffm
  2016-06-27 20:14 ` [PATCH v2 1/4] btrfs/048: extend _filter_btrfs_prop_error to handle additional errors jeffm
  2016-06-27 20:14 ` [PATCH v2 2/4] btrfs/124: test global metadata reservation reporting jeffm
@ 2016-06-27 20:14 ` jeffm
  2016-06-30  4:41   ` Eryu Guan
  2016-06-27 20:14 ` [PATCH v2 4/4] btrfs/126,127,128: test feature ioctl and sysfs interfaces jeffm
  2016-06-28  8:34 ` [PATCH v2 0/4] btrfs feature testing + props fix Eryu Guan
  4 siblings, 1 reply; 10+ messages in thread
From: jeffm @ 2016-06-27 20:14 UTC (permalink / raw)
  To: fstests, linux-btrfs; +Cc: Eryu Guan

From: Jeff Mahoney <jeffm@suse.com>

This tests the sysfs publishing for btrfs allocation and device
membership info under a number of different layouts, similar to the
btrfs replace test. We test the allocation files only for existence and
that they contain numerical values. We test the device membership
by mapping the devices used to create the file system to sysfs paths
and matching them against the paths used for the device membership
symlinks.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 common/btrfs        |   7 +++
 common/config       |   7 ++-
 tests/btrfs/125     | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/btrfs/125.out |   1 +
 tests/btrfs/group   |   1 +
 5 files changed, 190 insertions(+), 3 deletions(-)
 create mode 100755 tests/btrfs/125
 create mode 100644 tests/btrfs/125.out

diff --git a/common/btrfs b/common/btrfs
index b972b13..5828d0a 100644
--- a/common/btrfs
+++ b/common/btrfs
@@ -41,3 +41,10 @@ _require_btrfs_ioctl()
 		_notrun "btrfs ioctl $ioctl not implemented."
 	fi
 }
+
+# Requires the minimum size pool for largest btrfs RAID test
+_require_btrfs_raid_dev_pool()
+{
+	_require_scratch_dev_pool 4 # RAID10
+	_require_scratch_dev_pool_equal_size
+}
diff --git a/common/config b/common/config
index c25b1ec..8577924 100644
--- a/common/config
+++ b/common/config
@@ -201,13 +201,14 @@ export DEBUGFS_PROG="`set_prog_path debugfs`"
 # newer systems have udevadm command but older systems like RHEL5 don't.
 # But if neither one is available, just set it to "sleep 1" to wait for lv to
 # be settled
-UDEV_SETTLE_PROG="`set_prog_path udevadm`"
-if [ "$UDEV_SETTLE_PROG" == "" ]; then
+UDEVADM_PROG="`set_prog_path udevadm`"
+if [ "$UDEVADM_PROG" == "" ]; then
 	# try udevsettle command
 	UDEV_SETTLE_PROG="`set_prog_path udevsettle`"
 else
 	# udevadm is available, add 'settle' as subcommand
-	UDEV_SETTLE_PROG="$UDEV_SETTLE_PROG settle"
+	UDEV_SETTLE_PROG="$UDEVADM_PROG settle"
+	export UDEVADM_PROG
 fi
 # neither command is available, use sleep 1
 if [ "$UDEV_SETTLE_PROG" == "" ]; then
diff --git a/tests/btrfs/125 b/tests/btrfs/125
new file mode 100755
index 0000000..999a10e
--- /dev/null
+++ b/tests/btrfs/125
@@ -0,0 +1,177 @@
+#! /bin/bash
+# FS QA Test No. 125
+#
+# Test of the btrfs sysfs publishing
+#
+#-----------------------------------------------------------------------
+# Copyright (C) 2016 SUSE.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1
+
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/btrfs
+. ./common/filter
+
+# real QA test starts here
+_supported_fs btrfs
+_supported_os Linux
+_require_scratch
+_require_command "$UDEVADM_PROG" udevadm
+_require_test
+_require_btrfs_sysfs
+_require_btrfs_raid_dev_pool
+
+sysfs_root=$(_btrfs_get_sysfs $TEST_DIR)
+
+[ -d "$sysfs_root/allocation" ] || _notrun "sysfs allocation dir not found"
+[ -d "$sysfs_root/devices" ] || _notrun "sysfs devices dir not found"
+
+check_file()
+{
+	local file=$1
+	base="$(basename $(dirname $file))/$(basename $file)"
+	value="$(cat $file)"
+	if [ -n "$(echo $value | tr -d 0-9)" ]; then
+		echo "ERROR: $base: numerical value expected" \
+		     "(got $value)"
+	fi
+}
+
+check_chunk()
+{
+	path=$1
+	mkfs_options=$2
+
+	chunktype=$(basename $path)
+	[ -d "$path" ] || echo "No $chunktype directory."
+
+	for file in bytes_may_use bytes_pinned bytes_reserved bytes_used \
+		    disk_total disk_used flags total_bytes \
+		    total_bytes_pinned; do
+		check_file "$path/$file"
+	done
+
+	if [ "$chunktype" = "data" -o "$chunktype" = "mixed" ]; then
+		opt="-d"
+	elif [ "$chunktype" = "metadata" -o "$chunktype" = "system" ]; then
+		opt="-m"
+	fi
+
+	profile=$(echo $mkfs_options | sed -e "s/.*$opt \([[:alnum:]]*\).*/\1/")
+	[ -d "$path/$profile" ] || echo "No $profile dir for $chunktype"
+
+	for file in total_bytes used_bytes; do
+		check_file $path/$profile/$file
+	done
+}
+
+check_dev_link()
+{
+	local dev=$1
+	DEV="/sys/$($UDEVADM_PROG info --query=path $dev)"
+	DEV="$(readlink -f $DEV)"
+	found=false
+	for link in $sysfs_base/devices/*; do
+		LINK="$(readlink -f $link)"
+		if [ "$LINK" = "$DEV" ]; then
+			found=true
+			break
+		fi
+	done
+	if ! $found; then
+		echo "Symlink for $dev missing in $sysfs_base/devices"
+	fi
+	return 0
+}
+
+workout()
+{
+	local mkfs_options="$1"
+	local num_devs4raid="$2"
+	local fssize
+	local used_devs=""
+
+	if [ "$num_devs4raid" -gt 1 ]; then
+		used_devs=$(echo $SCRATCH_DEV_POOL|tr '\t' ' '| \
+			    cut -d ' ' -f 2-$num_devs4raid)
+	fi
+
+	# We check the error code since mkfs can fail if the devices
+	# are specified incorrectly but we may still have a file system
+	# from a prior run.
+	_scratch_mkfs $mkfs_options $used_devs 2>> $seqres.full || \
+		_fail "mkfs failed"
+
+	_scratch_mount
+
+	# Check allocation
+	sysfs_base="$(_btrfs_get_sysfs $SCRATCH_MNT)"
+
+	mixed=false
+	case "$mkfs_options" in
+	*-M*)
+		mixed=true;
+		;;
+	esac
+
+	check_chunk "$sysfs_base/allocation/system" "$mkfs_options"
+	if $mixed; then
+		check_chunk "$sysfs_base/allocation/mixed" "$mkfs_options"
+	else
+		check_chunk "$sysfs_base/allocation/data" "$mkfs_options"
+		check_chunk "$sysfs_base/allocation/metadata" "$mkfs_options"
+	fi
+
+	for dev in $used_devs; do
+		check_dev_link $dev
+	done
+
+	_scratch_unmount
+}
+
+workout "-m single -d single" 1
+workout "-m single -d single -M" 1
+workout "-m dup -d single" 1
+workout "-m dup -d dup -M" 1
+workout "-m raid0 -d raid0" 2
+workout "-m raid1 -d raid1" 2
+workout "-m raid5 -d raid5" 2
+workout "-m raid6 -d raid6" 3
+workout "-m raid10 -d raid10" 4
+
+status=0
+exit
diff --git a/tests/btrfs/125.out b/tests/btrfs/125.out
new file mode 100644
index 0000000..4f22ab0
--- /dev/null
+++ b/tests/btrfs/125.out
@@ -0,0 +1 @@
+QA output created by 125
diff --git a/tests/btrfs/group b/tests/btrfs/group
index 8b5050e..3535f02 100644
--- a/tests/btrfs/group
+++ b/tests/btrfs/group
@@ -127,3 +127,4 @@
 122 auto quick snapshot qgroup
 123 auto quick qgroup
 124 auto quick metadata
+125 auto quick metadata
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 4/4] btrfs/126,127,128: test feature ioctl and sysfs interfaces
  2016-06-27 20:14 [PATCH v2 0/4] btrfs feature testing + props fix jeffm
                   ` (2 preceding siblings ...)
  2016-06-27 20:14 ` [PATCH v2 3/4] btrfs/125: test sysfs exports of allocation and device membership info jeffm
@ 2016-06-27 20:14 ` jeffm
  2016-06-30  6:30   ` Eryu Guan
  2016-06-28  8:34 ` [PATCH v2 0/4] btrfs feature testing + props fix Eryu Guan
  4 siblings, 1 reply; 10+ messages in thread
From: jeffm @ 2016-06-27 20:14 UTC (permalink / raw)
  To: fstests, linux-btrfs; +Cc: Eryu Guan

From: Jeff Mahoney <jeffm@suse.com>

This tests the exporting of feature information from the kernel via
sysfs and ioctl. The first test works whether the sysfs permissions
are correct, if the information exported via sysfs matches
what the ioctls are reporting, and if they both match the on-disk
superblock's version of the feature sets. The second and third tests
test online setting and clearing of feature bits via the sysfs and
ioctl interfaces, checking whether they match the on-disk super on
each cycle.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 common/btrfs             | 203 +++++++++++++++++++++++++++++++++++++++
 src/btrfs_ioctl_helper.c |  88 +++++++++++++++++
 tests/btrfs/126          | 244 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/btrfs/126.out      |   1 +
 tests/btrfs/127          | 166 ++++++++++++++++++++++++++++++++
 tests/btrfs/127.out      |   1 +
 tests/btrfs/128          | 128 +++++++++++++++++++++++++
 tests/btrfs/128.out      |   1 +
 tests/btrfs/group        |   3 +
 9 files changed, 835 insertions(+)
 create mode 100755 tests/btrfs/126
 create mode 100644 tests/btrfs/126.out
 create mode 100755 tests/btrfs/127
 create mode 100644 tests/btrfs/127.out
 create mode 100755 tests/btrfs/128
 create mode 100644 tests/btrfs/128.out

diff --git a/common/btrfs b/common/btrfs
index 5828d0a..2d7d0ce 100644
--- a/common/btrfs
+++ b/common/btrfs
@@ -48,3 +48,206 @@ _require_btrfs_raid_dev_pool()
 	_require_scratch_dev_pool 4 # RAID10
 	_require_scratch_dev_pool_equal_size
 }
+
+# TODO Add tool to enable and test unknown feature bits
+_btrfs_feature_lookup() {
+	local name=$1
+	class=""
+	case "$name" in
+	mixed_backref)	class=incompat; bit=0x1 ;;
+	default_subvol)	class=incompat; bit=0x2 ;;
+	mixed_groups)	class=incompat; bit=0x4 ;;
+	compress_lzo)	class=incompat; bit=0x8 ;;
+	compress_lsov2)	class=incompat; bit=0x10 ;;
+	big_metadata)	class=incompat; bit=0x20 ;;
+	extended_iref)	class=incompat; bit=0x40 ;;
+	raid56)		class=incompat; bit=0x80 ;;
+	skinny_metadata)class=incompat; bit=0x100 ;;
+	compat:*)	class=compat; bit=${name##compat:} ;;
+	compat_ro:*)	class=compat_ro; bit=${name##compat_ro:} ;;
+	incompat:*)	class=incompat; bit=${name##incompat:} ;;
+	esac
+	if [ -z "$class" ]; then
+		echo "Unknown feature name $name. xfstests needs updating." \
+		     " Skipping the test of sysfs values to superblock values" \
+		     >&2
+	fi
+
+	echo "$class/$bit"
+}
+
+_btrfs_feature_get_class() {
+	bits=$(_btrfs_feature_lookup $1)
+	echo ${bits%/*}
+}
+
+_btrfs_feature_get_bit() {
+	bits=$(_btrfs_feature_lookup $1)
+	echo ${bits#*/}
+}
+
+_btrfs_feature_class_to_index()
+{
+	local class=$1
+	local index=0
+
+	case "$class" in
+	compat) index=0 ;;
+	compat_ro) index=1 ;;
+	incompat) index=2 ;;
+	*) echo "Invalid class name $class" >&2
+	esac
+
+	echo $index
+}
+
+# The ioctl helper outputs the supported feature flags as a series of
+# 9 hex numbers, which represent bitfields.
+# These 9 values represent 3 sets of 3 values.
+# supported flags: compat compat_ro incompat, starting at index 0
+# settable online: compat compat_ro incompat, starting at index 3
+# clearable online: compat compat_ro incompat, starting at index 6
+# The returned mask is: 0x1 settable | 0x2 clearable
+_btrfs_feature_ioctl_writeable_mask()
+{
+	local feature=$1
+	local mnt=$2
+	local index=0
+
+	# This usually won't matter.  The supported bits are fs-module global.
+	if [ -z "$mnt" ]; then
+		mnt=$TEST_DIR
+	fi
+
+	class=$(_btrfs_feature_get_class $1)
+	bit=$(_btrfs_feature_get_bit $1)
+	index=$(_btrfs_feature_class_to_index $class)
+
+	local set_index=$(( $index + 3 ))
+	local clear_index=$(( $index + 6 ))
+
+	out=$(src/btrfs_ioctl_helper $mnt GET_SUPPORTED_FEATURES)
+	set -- $out
+	supp_features=($@)
+
+	settable=$(( ${supp_features[$set_index]} & $bit ))
+	clearable=$(( ${supp_features[$clear_index]} & $bit ))
+
+	val=0
+	if [ "$settable" -ne 0 ]; then
+		val=$(( $val | 1 ))
+	fi
+	if [ "$clearable" -ne 0 ]; then
+		val=$(( $val | 2 ))
+	fi
+
+	echo $val
+}
+
+_btrfs_feature_ioctl_index_settable_mask()
+{
+	local class_index=$1
+	local mnt=$2
+
+	# This usually won't matter.  The supported bits are fs-module global.
+	if [ -z "$mnt" ]; then
+		mnt=$TEST_DIR
+	fi
+
+	local set_index=$(( $class_index + 3 ))
+
+	out=$(src/btrfs_ioctl_helper $mnt GET_SUPPORTED_FEATURES)
+	set -- $out
+	supp_features=($@)
+
+	echo $(( ${supp_features[$set_index]} ))
+}
+
+_btrfs_feature_ioctl_index_clearable_mask()
+{
+	local class_index=$1
+	local mnt=$2
+	local index=0
+
+	# This usually won't matter.  The supported bits are fs-module global.
+	if [ -z "$mnt" ]; then
+		mnt=$TEST_DIR
+	fi
+
+	local set_index=$(( $class_index + 6 ))
+
+	out=$(src/btrfs_ioctl_helper $mnt GET_SUPPORTED_FEATURES)
+	set -- $out
+	supp_features=($@)
+
+	echo $(( ${supp_features[$clear_index]} ))
+}
+
+_btrfs_feature_ioctl_is_writeable()
+{
+	local feature=$1
+	local mnt=$2
+	local mask=$(_btrfs_feature_ioctl_writeable_mask $feature $2)
+
+	test "$mask" -ne 0
+	return $?
+}
+
+_btrfs_feature_ioctl_is_settable()
+{
+	local feature=$1
+	local mnt=$2
+	local mask=$(_btrfs_feature_ioctl_writeable_mask $feature $2)
+
+	if [ "$(( $mask & 1 ))" -ne 0 ]; then
+		echo "true"
+	else
+		echo "false"
+	fi
+}
+
+_btrfs_feature_ioctl_is_settable()
+{
+	local feature=$1
+	local mnt=$2
+	local mask=$(_btrfs_feature_ioctl_writeable_mask $feature $2)
+
+	if [ "$(( $mask & 2 ))" -ne 0 ]; then
+		echo "true"
+	else
+		echo "false"
+	fi
+}
+
+_btrfs_feature_sysfs_is_settable()
+{
+	local feature=$1
+
+	val=$(cat /sys/fs/btrfs/features/$feature)
+
+	if [ "$(( $val & 2 ))" -eq 2 ]; then
+		echo "true"
+	else
+		echo "false"
+	fi
+}
+
+_btrfs_feature_sysfs_is_clearable()
+{
+	local feature=$1
+
+	val=$(cat /sys/fs/btrfs/features/$feature)
+
+	if [ "$(( $val & 2 ))" -eq 2 ]; then
+		echo "true"
+	else
+		echo "false"
+	fi
+}
+
+_btrfs_feature_disk_get_flags()
+{
+	local dev=$1
+	local class=$2
+	$BTRFS_SHOW_SUPER_PROG $dev | grep ^${class}_flags | awk '{print $NF}'
+}
diff --git a/src/btrfs_ioctl_helper.c b/src/btrfs_ioctl_helper.c
index b6eb924..4344bdc 100644
--- a/src/btrfs_ioctl_helper.c
+++ b/src/btrfs_ioctl_helper.c
@@ -30,6 +30,21 @@ struct btrfs_ioctl_space_args {
 #define BTRFS_SPACE_INFO_GLOBAL_RSV    (1ULL << 49)
 #endif
 
+#ifndef BTRFS_IOC_GET_FEATURES
+struct btrfs_ioctl_feature_flags {
+	uint64_t compat_flags;
+	uint64_t compat_ro_flags;
+	uint64_t incompat_flags;
+};
+
+#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
+                                   struct btrfs_ioctl_feature_flags)
+#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \
+                                   struct btrfs_ioctl_feature_flags[2])
+#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
+                                   struct btrfs_ioctl_feature_flags[3])
+#endif
+
 static int global_rsv_ioctl(int fd, int argc, char *argv[])
 {
 	struct btrfs_ioctl_space_args arg;
@@ -67,6 +82,76 @@ static int global_rsv_ioctl(int fd, int argc, char *argv[])
 	return -ENOENT;
 }
 
+static int get_features_ioctl(int fd, int argc, char *argv[])
+{
+	struct btrfs_ioctl_feature_flags flags;
+	int ret = ioctl(fd, BTRFS_IOC_GET_FEATURES, &flags);
+	if (ret)
+		return -errno;
+
+	printf("0x%llx 0x%llx 0x%llx\n",
+	       (unsigned long long)flags.compat_flags,
+	       (unsigned long long)flags.compat_ro_flags,
+	       (unsigned long long)flags.incompat_flags);
+	return 0;
+}
+
+static int set_features_ioctl(int fd, int argc, char *argv[])
+{
+	struct btrfs_ioctl_feature_flags flags[2];
+	uint64_t bit, *bits, *mask;
+	if (argc != 3)
+		goto usage;
+
+	memset(flags, 0, sizeof(flags));
+
+	errno = 0;
+	bit = strtoull(argv[2], NULL, 10);
+	if (errno)
+		goto usage;
+
+	if (strcmp(argv[1], "compat") == 0) {
+		mask = &flags[0].compat_flags;
+		bits = &flags[1].compat_flags;
+	} else if (strcmp(argv[1], "compat_ro") == 0) {
+		mask = &flags[0].compat_ro_flags;
+		bits = &flags[1].compat_ro_flags;
+	} else if (strcmp(argv[1], "incompat") == 0) {
+		mask = &flags[0].incompat_flags;
+		bits = &flags[1].incompat_flags;
+	} else
+		goto usage;
+
+	*mask |= bit;
+
+	if (strcmp(argv[0], "set") == 0)
+		*bits |= bit;
+
+	return ioctl(fd, BTRFS_IOC_SET_FEATURES, &flags);
+usage:
+	fprintf(stderr, "usage: SET_FEATURES <set|clear> <compat|compat_ro|incompat> <base-10 bitmask>\n");
+	return -EINVAL;
+}
+
+static int get_supported_features_ioctl(int fd, int argc, char *argv[])
+{
+	struct btrfs_ioctl_feature_flags flags[3];
+	int ret;
+	int i;
+
+	ret = ioctl(fd, BTRFS_IOC_GET_SUPPORTED_FEATURES, &flags);
+	if (ret)
+		return -errno;
+
+	for (i = 0; i < 3; i++)
+		printf("0x%llx 0x%llx 0x%llx ",
+		       (unsigned long long)flags[i].compat_flags,
+		       (unsigned long long)flags[i].compat_ro_flags,
+		       (unsigned long long)flags[i].incompat_flags);
+
+	printf("\n");
+	return 0;
+}
 #define IOCTL_TABLE_ENTRY(_ioctl_name, _handler) \
 	{ .name = #_ioctl_name, .ioctl_cmd = BTRFS_IOC_##_ioctl_name, \
 	  .handler = _handler, }
@@ -79,6 +164,9 @@ struct ioctl_table_entry {
 
 static struct ioctl_table_entry ioctls[] = {
 	IOCTL_TABLE_ENTRY(SPACE_INFO, global_rsv_ioctl),
+	IOCTL_TABLE_ENTRY(GET_FEATURES, get_features_ioctl),
+	IOCTL_TABLE_ENTRY(SET_FEATURES, set_features_ioctl),
+	IOCTL_TABLE_ENTRY(GET_SUPPORTED_FEATURES, get_supported_features_ioctl),
 };
 
 int
diff --git a/tests/btrfs/126 b/tests/btrfs/126
new file mode 100755
index 0000000..71307a3
--- /dev/null
+++ b/tests/btrfs/126
@@ -0,0 +1,244 @@
+#!/bin/bash
+# FA QA Test No. 126
+#
+# Test online feature publishing
+#
+# This test doesn't test the changing of features. It does test that
+# the proper publishing bits and permissions match up with
+# the expected values.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 SUSE, All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+
+seq=$(basename $0)
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=$(pwd)
+tmp=/tmp/$$
+status=1
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+        cd /
+        rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/btrfs
+. ./common/filter.btrfs
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+_supported_fs btrfs
+_supported_os Linux
+_require_scratch
+_require_command "$BTRFS_SHOW_SUPER_PROG" btrfs-show-super
+_require_test_program btrfs_ioctl_helper
+_require_test
+_require_btrfs_ioctl GET_FEATURES $TEST_DIR
+_require_btrfs_ioctl GET_SUPPORTED_FEATURES $TEST_DIR
+_require_btrfs_sysfs
+
+IOCTL="src/btrfs_ioctl_helper"
+
+sysfs_root="/sys/fs/btrfs"
+[ -d "$sysfs_root/features" ] || _notrun "sysfs features dir not found"
+[ -d "$(_btrfs_get_sysfs)/features" ] || _notrun "sysfs per-fs features dir not found"
+
+_scratch_mkfs 2>> $seqres.full
+_scratch_mount
+sysfs_fsroot=$(_btrfs_get_sysfs $SCRATCH_MNT)
+
+
+# test -w will always return true if root is making the call.
+# This would be true in most cases, but for sysfs files, the permissions
+# are enforced even for root.
+is_writeable()
+{
+	local file=$1
+	mode=$(stat -c "0%a" "$file")
+	mode=$(( $mode & 0200 ))
+
+	[ "$mode" -eq 0 ] && return 1
+	return 0
+}
+
+# Check enabled features in sysfs vs what the superblock claims
+sysfs_features=(0 0 0)
+
+for file in $sysfs_fsroot/features/*; do
+	feature=$(basename $file)
+	supported=$(cat $sysfs_root/features/$feature)
+
+	case "$supported" in
+	0|1|2|3) ;;
+	*)
+		echo "Invalid value $supported in features/$feature"
+		continue
+	esac
+
+	if [ ! -e "$sysfs_root/features/$feature" ]; then
+		echo "fsid/features/$feature exists but features/$feature does not."
+		continue
+	fi
+
+	val=$(cat $file)
+
+	if [ -n "$(echo -n $supported| tr -d 0-9)" ]; then
+		echo "features/$feature has invalid contents $supported"
+		continue
+	fi
+	if [ -n "$(echo -n $val| tr -d 0-9)" ]; then
+		echo "fsid/features/$feature has invalid contents $val"
+		continue
+	fi
+	val=$(( $val ))
+
+	if [ "$supported" -eq 0 ]; then
+		if is_writeable "$file"; then
+			echo "fsid/features/$feature is writable but features/$feature has a 0 value."
+		fi
+
+		if _btrfs_feature_ioctl_is_writeable $feature; then
+			echo "fsid/features/$feature is not writeable but ioctl says it is"
+		fi
+	else
+		if ! is_writeable "$file"; then
+			echo "fsid/features/$feature is not writable but features/$feature has a nonzero value $val."
+		fi
+
+		if ! _btrfs_feature_ioctl_is_writeable $feature; then
+			echo "fsid/features/$feature is writeable but ioctl says it isn't"
+		fi
+	fi
+
+	bit=$(_btrfs_feature_get_bit $feature)
+	class=$(_btrfs_feature_get_class $feature)
+	if [ "$class" = "compat" ]; then
+		sysfs_features[0]=$(( ${sysfs_features[0]} | $bit ))
+	elif [ "$class" = "compat_ro" ]; then
+		sysfs_features[1]=$(( ${sysfs_features[1]} | $bit ))
+	elif [ "$class" = "incompat" ]; then
+		sysfs_features[2]=$(( ${sysfs_features[2]} | $bit ))
+	fi
+done
+
+for file in $sysfs_root/features/*; do
+	feature=$(basename $file)
+	val=$(cat $file)
+	if [ "$val" -gt 0 ]; then
+		if [ ! -e "$sysfs_fsroot/features/$feature" ]; then
+			echo "features/$feature has a nonzero value ($val)" \
+			     "but fsid/features/$feature doesn't exist"
+		fi
+		if ! is_writeable "$sysfs_fsroot/features/$feature"; then
+			echo "features/$feature has a nonzero value ($val)" \
+			     "but fsid/features/$feature is not writable"
+		fi
+		if ! _btrfs_feature_ioctl_is_writeable $feature; then
+			echo "features/$feature has a nonzero value ($val) " \
+			     "but ioctl says it is not writeable."
+		fi
+
+		ioctl_settable=$(_btrfs_feature_ioctl_is_settable $feature)
+		sysfs_settable=$(_btrfs_feature_sysfs_is_settable $feature)
+
+		if $sysfs_settable && ! $ioctl_settable; then
+			echo "features/$feature exports settable " \
+			      "but ioctl does not"
+		fi
+		if ! $sysfs_settable && $ioctl_settable; then
+			echo "features/$feature does not export settable " \
+			      "but ioctl does"
+		fi
+
+		ioctl_clearable=$(_btrfs_feature_ioctl_is_settable $feature)
+		sysfs_clearable=$(_btrfs_feature_sysfs_is_settable $feature)
+
+		if $sysfs_clearable && ! $ioctl_clearable; then
+			echo "features/$feature exports clearable " \
+			      "but ioctl does not"
+		fi
+		if ! $sysfs_clearable && $ioctl_clearable; then
+			echo "features/$feature does not export clearable " \
+			      "but ioctl does"
+		fi
+		continue
+	fi
+
+	# This is ok; The file system supports this feature but the mounted
+	# file system doesn't enable it.
+	[ -e "$sysfs_fsroot/features/$feature" ] || continue
+
+	if is_writeable "$sysfs_fsroot/features/$feature"; then
+		echo "features/$feature has a zero value but" \
+		     "fsid/features/$feature is writable."
+	fi
+
+	if _btrfs_feature_ioctl_is_writeable $feature; then
+		echo "$feature isn't writable but ioctl says it is"
+	fi
+done
+
+fields=("compat" "compat_ro" "incompat")
+
+check_ioctl_flags()
+{
+	local class=$1
+	local flags=$(( $2 ))
+	local disk_flags=$(( $3 ))
+
+	if [ "$flags" -ne "$disk_flags" ]; then
+		echo "ioctl returned different $class flags" \
+		     "($flags) than those contained in superblock" \
+		     "($disk_flags)"
+	fi
+}
+
+check_sysfs_flags()
+{
+	local class=$1
+	local sysfs_flags=$(( $2 ))
+	local disk_flags=$(( $3 ))
+
+	if [ "$sysfs_flags" -ne "$disk_flags" ]; then
+		echo "sysfs returned different $class" \
+		     "flags ($flags) than those contained in" \
+		     "superblock ($disk_flags)" >&2
+	fi
+}
+
+# ioctl
+out=$($IOCTL $SCRATCH_MNT GET_FEATURES)
+set -- $out
+ioctl_features=($@)
+
+for index in $(seq 0 2); do
+	class=${fields[$index]}
+	disk_flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
+	check_ioctl_flags "$class" "${ioctl_features[$index]}" "$disk_flags"
+	check_sysfs_flags "$class" "${sysfs_features[$index]}" "$disk_flags"
+done
+
+_scratch_unmount
+
+status=0
+exit
diff --git a/tests/btrfs/126.out b/tests/btrfs/126.out
new file mode 100644
index 0000000..f162d8b
--- /dev/null
+++ b/tests/btrfs/126.out
@@ -0,0 +1 @@
+QA output created by 126
diff --git a/tests/btrfs/127 b/tests/btrfs/127
new file mode 100755
index 0000000..191beff
--- /dev/null
+++ b/tests/btrfs/127
@@ -0,0 +1,166 @@
+#!/bin/bash
+# FA QA Test No. 127
+#
+# Test online feature changing via ioctl
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 SUSE, All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+
+seq=$(basename $0)
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=$(pwd)
+tmp=/tmp/$$
+status=1
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+        cd /
+        rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/btrfs
+. ./common/filter.btrfs
+
+rm -f $seqres.full
+
+_supported_fs btrfs
+_supported_os Linux
+_require_scratch
+_require_command "$BTRFS_SHOW_SUPER_PROG" btrfs-show-super
+_require_test_program btrfs_ioctl_helper
+
+IOCTL=src/btrfs_ioctl_helper
+
+# 3 values, one for each each of the fields
+update_features()
+{
+	local ioctl_values=$($IOCTL $SCRATCH_MNT GET_FEATURES)
+	set -- $ioctl_values
+	features=($@)
+}
+
+test_set_feature()
+{
+	local field=$1
+	local bits=$2
+	local class=${fields[$field]}
+	local old=${features[$field]}
+	msg=$($IOCTL $SCRATCH_MNT SET_FEATURES set $class $bits)
+	update_features
+	local new=${features[$field]}
+
+	expected=$(( $old | $bits ))
+	new=$(( $new ))
+	if [ "$expected" -ne "$new" ]; then
+		echo "Feature setting failed; Got $new, expected $expected"
+		return 1
+	fi
+}
+
+test_clear_feature()
+{
+	local field=$1
+	local bits=$2
+	local class=${fields[$field]}
+	local old=${features[$field]}
+	msg=$($IOCTL $SCRATCH_MNT SET_FEATURES clear $class $bits)
+	update_features
+	local new="${features[$field]}"
+
+	expected=$(( $old & ~$bits ))
+	new=$(( $new ))
+	if [ "$expected" -ne "$new" ]; then
+		echo "Feature clearing failed; Got $new, expected $expected"
+	fi
+	return 0
+}
+
+fields=("compat" "compat_ro" "incompat")
+
+check_flags()
+{
+	local index=$1
+	local expected=$(( $2 ))
+	local class=${fields[$index]}
+
+	local disk_flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
+
+	disk_flags=$(( $disk_flags ))
+
+	if [ "$disk_flags" -ne "$expected" ]; then
+		echo "mismatch: $disk_flags != $expected"
+	fi
+}
+
+_scratch_mkfs 2>> $seqres.full
+_scratch_mount
+
+update_features
+
+
+# Cycle through settable features.
+# Set the feature
+# Reload ioctl version and test against expected new value
+# Unmount and test against expected new value
+# Remount
+did_set=false
+
+for field in $(seq 0 2); do
+	fset="$(_btrfs_feature_ioctl_index_settable_mask $field)"
+	[ -z "$fset" ] && break
+	for n in $(seq 0 63); do
+		old="${features[$field]}"
+		v="$(( $fset & (1 << $n) ))"
+		[ "$v" -eq 0 ] && continue
+		test_set_feature $field $v
+		_scratch_unmount
+		expected="$(( $old | $v ))"
+		check_flags "$field" "$expected"
+		_scratch_mount
+		did_set=true
+	done
+done
+$did_set || echo "No online-settable features to test." >> $seqres.full
+
+# Repeat with clearing features
+id_clear=false
+for field in $(seq 0 2); do
+	fclear="$(_btrfs_feature_ioctl_index_clearable_mask $field)"
+	[ -z "$fclear" ] && break
+	for n in $(seq 0 63); do
+		v="$(( $fclear & (1 << $n) ))"
+		[ "$v" -eq 0 ] && continue
+
+		test_clear_feature $field $v
+		_scratch_unmount
+		expected=$(( $old &~ $v ))
+		check_flags $field $expected
+		_scratch_mount
+		did_clear=true
+	done
+done
+$did_clear || echo "No online-clearable features to test." >> $seqres.full
+
+_scratch_unmount
+
+status=0
+exit
diff --git a/tests/btrfs/127.out b/tests/btrfs/127.out
new file mode 100644
index 0000000..09d2be1
--- /dev/null
+++ b/tests/btrfs/127.out
@@ -0,0 +1 @@
+QA output created by 127
diff --git a/tests/btrfs/128 b/tests/btrfs/128
new file mode 100755
index 0000000..46160d9
--- /dev/null
+++ b/tests/btrfs/128
@@ -0,0 +1,128 @@
+#!/bin/bash
+# FA QA Test No. 128
+#
+# Test online feature changing via sysfs
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 SUSE, All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+
+seq=$(basename $0)
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=$(pwd)
+tmp=/tmp/$$
+status=1
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+        cd /
+        rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/btrfs
+. ./common/filter.btrfs
+
+rm -f $seqres.full
+
+_supported_fs btrfs
+_supported_os Linux
+_require_scratch
+_require_command $BTRFS_SHOW_SUPER_PROG
+_require_test
+_require_btrfs_sysfs
+
+sysfs_root="/sys/fs/btrfs"
+[ -d "$sysfs_root/features" ] || _notrun "sysfs features dir not found"
+sysfs_fsroot=$(_btrfs_get_sysfs)
+[ -d "$sysfs_fsroot/features" ] || _notrun "sysfs per-fs features dir not found"
+
+check_flags() {
+	local class=$1
+	local expected=$(( $2 ))
+	disk_flags="$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)"
+	disk_flags=$(( $disk_flags ))
+	if [ "$disk_flags" != "$expected" ]; then
+		echo "mismatch: $disk_flags-$expected"
+	fi
+}
+
+_scratch_mkfs 2>> $seqres.full
+fields=("compat" "compat_ro" "incompat")
+sysfs_base="/sys/fs/btrfs"
+settable=""
+clearable=""
+
+# Gather up the features the kernel knows about
+_scratch_mount
+
+sysfs_fsroot=$(_btrfs_get_sysfs $SCRATCH_MNT)
+
+for file in $sysfs_base/features/*; do
+	feature=$(basename $file)
+	val=$(cat $file)
+	if [ "$(( $val & 0x1 ))" -eq 1 ]; then
+		settable="$settable $feature"
+	fi
+	if [ "$(( $val & 0x2 ))" -eq 2 ]; then
+		clearable="$clearable $feature"
+	fi
+done
+_scratch_unmount
+
+did_set=false
+for feature in $settable; do
+	class=$(_btrfs_feature_get_class $feature)
+	bit=$(_btrfs_feature_get_bit $feature)
+	flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
+	flags=$(( $flags ))
+	_scratch_mount
+	val=$(cat $sysfs_fsroot/features/$feature)
+	echo 1 > $sysfs_fsroot/features/$feature
+	newval=$(cat $sysfs_fsroot/features/$feature)
+	[ "$newval" -ne 1 ] && echo "Setting feature $feature failed"
+	_scratch_unmount
+	check_flags $class $(( $flags | $bit ))
+	did_set=true
+done
+$did_set || echo "No online-settable features to test." >> $seqres.full
+
+did_clear=false
+for feature in $clearable; do
+	class=$(_btrfs_feature_get_class $feature)
+	bit=$(_btrfs_feature_get_bit $feature)
+	flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
+	flags=$(( $flags ))
+
+	_scratch_mount
+	val=$(cat $sysfs_fsroot/features/$feature)
+	[ "$val" -ne 1 ] && continue
+	echo 0 > $sysfs_fsroot/features/$feature
+	newval=$(cat $sysfs_fsroot/features/$feature)
+	[ "$newval" -ne 0 ] && echo "Clearing feature $feature was ignored."
+	_scratch_unmount
+	check_flags $class $(( $flags & ~$bit ))
+	did_clear=true
+done
+$did_clear || echo "No online-clearable features to test." >> $seqres.full
+
+# Still unmounted from set/clear tests
+status=0
+exit
diff --git a/tests/btrfs/128.out b/tests/btrfs/128.out
new file mode 100644
index 0000000..34f24a3
--- /dev/null
+++ b/tests/btrfs/128.out
@@ -0,0 +1 @@
+QA output created by 128
diff --git a/tests/btrfs/group b/tests/btrfs/group
index 3535f02..e76265d 100644
--- a/tests/btrfs/group
+++ b/tests/btrfs/group
@@ -128,3 +128,6 @@
 123 auto quick qgroup
 124 auto quick metadata
 125 auto quick metadata
+126 auto quick metadata
+127 auto quick metadata
+128 auto quick metadata
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 0/4] btrfs feature testing + props fix
  2016-06-27 20:14 [PATCH v2 0/4] btrfs feature testing + props fix jeffm
                   ` (3 preceding siblings ...)
  2016-06-27 20:14 ` [PATCH v2 4/4] btrfs/126,127,128: test feature ioctl and sysfs interfaces jeffm
@ 2016-06-28  8:34 ` Eryu Guan
  4 siblings, 0 replies; 10+ messages in thread
From: Eryu Guan @ 2016-06-28  8:34 UTC (permalink / raw)
  To: jeffm; +Cc: fstests, linux-btrfs

On Mon, Jun 27, 2016 at 04:14:10PM -0400, jeffm@suse.com wrote:
> From: Jeff Mahoney <jeffm@suse.com>
> 
> Hi all -
> 
> Thanks, Eryu, for the review.  The btrfs feature testing changes were a
> patchet I wrote three years ago, and it looks like significant cleanup
> has happened in the xfstests since then.  I'm sorry for the level of the
> review you had to do for them, but do appreciate that you did.

No problem :) Thanks for updating the tests! I'll review again, but that
may take some time.

Thanks,
Eryu

> 
> This version should fix the outstanding issues, including some issues
> with the tests themselves, where e.g. the 32MB reserved size was file
> system-size (and implementation) dependent.  Most notably, since these
> tests share some common functionality that ultimately hit ~250 lines, I
> chose to create a new common/btrfs library.  Other than that, I tried to
> meet the level of consistency you were looking for with just printing
> errors instead of failing, not depending on error codes, etc.
> 
> Thanks,
> 
> -Jeff
> 
> ---
> 
> Jeff Mahoney (4):
>   btrfs/048: extend _filter_btrfs_prop_error to handle additional errors
>   btrfs/124: test global metadata reservation reporting
>   btrfs/125: test sysfs exports of allocation and device membership info
>   btrfs/126,127,128: test feature ioctl and sysfs interfaces
> 
>  .gitignore               |   1 +
>  common/btrfs             | 253 +++++++++++++++++++++++++++++++++++++++++++++++
>  common/config            |   7 +-
>  common/filter.btrfs      |  10 +-
>  src/Makefile             |   3 +-
>  src/btrfs_ioctl_helper.c | 220 +++++++++++++++++++++++++++++++++++++++++
>  tests/btrfs/048          |   6 +-
>  tests/btrfs/048.out      |   4 +-
>  tests/btrfs/124          |  84 ++++++++++++++++
>  tests/btrfs/124.out      |   1 +
>  tests/btrfs/125          | 177 +++++++++++++++++++++++++++++++++
>  tests/btrfs/125.out      |   1 +
>  tests/btrfs/126          | 244 +++++++++++++++++++++++++++++++++++++++++++++
>  tests/btrfs/126.out      |   1 +
>  tests/btrfs/127          | 166 +++++++++++++++++++++++++++++++
>  tests/btrfs/127.out      |   1 +
>  tests/btrfs/128          | 128 ++++++++++++++++++++++++
>  tests/btrfs/128.out      |   1 +
>  tests/btrfs/group        |   5 +
>  19 files changed, 1302 insertions(+), 11 deletions(-)
>  create mode 100644 common/btrfs
>  create mode 100644 src/btrfs_ioctl_helper.c
>  create mode 100755 tests/btrfs/124
>  create mode 100644 tests/btrfs/124.out
>  create mode 100755 tests/btrfs/125
>  create mode 100644 tests/btrfs/125.out
>  create mode 100755 tests/btrfs/126
>  create mode 100644 tests/btrfs/126.out
>  create mode 100755 tests/btrfs/127
>  create mode 100644 tests/btrfs/127.out
>  create mode 100755 tests/btrfs/128
>  create mode 100644 tests/btrfs/128.out
> 
> -- 
> 1.8.5.6
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/4] btrfs/048: extend _filter_btrfs_prop_error to handle additional errors
  2016-06-27 20:14 ` [PATCH v2 1/4] btrfs/048: extend _filter_btrfs_prop_error to handle additional errors jeffm
@ 2016-06-29 13:48   ` Eryu Guan
  0 siblings, 0 replies; 10+ messages in thread
From: Eryu Guan @ 2016-06-29 13:48 UTC (permalink / raw)
  To: jeffm; +Cc: fstests, linux-btrfs

On Mon, Jun 27, 2016 at 04:14:11PM -0400, jeffm@suse.com wrote:
> From: Jeff Mahoney <jeffm@suse.com>
> 
> btrfsprogs v4.5.3 changed the formatting of some error messages.  This
> patch extends the filter for btrfs prop to handle those.
> 
> Signed-off-by: Jeff Mahoney <jeffm@suse.com>

Reviewed-by: Eryu Guan <eguan@redhat.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/4] btrfs/124: test global metadata reservation reporting
  2016-06-27 20:14 ` [PATCH v2 2/4] btrfs/124: test global metadata reservation reporting jeffm
@ 2016-06-30  4:07   ` Eryu Guan
  0 siblings, 0 replies; 10+ messages in thread
From: Eryu Guan @ 2016-06-30  4:07 UTC (permalink / raw)
  To: jeffm; +Cc: fstests, linux-btrfs

On Mon, Jun 27, 2016 at 04:14:12PM -0400, jeffm@suse.com wrote:
> From: Jeff Mahoney <jeffm@suse.com>
> 
> Btrfs can now report the size of the global metadata reservation
> via ioctl and sysfs.
> 
> This test confirms that we get sane results on an empty file system.
> 
> Signed-off-by: Jeff Mahoney <jeffm@suse.com>
> ---
>  .gitignore               |   1 +
>  common/btrfs             |  43 +++++++++++++++

We have all sorts of btrfs-specific helpers in common/rc now, and IIRC
Dave said he had a pending patch to move all the btrfs helpers to
commom/btrfs. So I think for now it's OK to add new btrfs helpers just
to common/rc.

>  src/Makefile             |   3 +-
>  src/btrfs_ioctl_helper.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++
>  tests/btrfs/124          |  84 ++++++++++++++++++++++++++++++
>  tests/btrfs/124.out      |   1 +
>  tests/btrfs/group        |   1 +
>  7 files changed, 264 insertions(+), 1 deletion(-)
>  create mode 100644 common/btrfs
>  create mode 100644 src/btrfs_ioctl_helper.c
>  create mode 100755 tests/btrfs/124
>  create mode 100644 tests/btrfs/124.out
> 
> diff --git a/.gitignore b/.gitignore
> index 28bd180..0e4f2a1 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -39,6 +39,7 @@
>  /src/append_reader
>  /src/append_writer
>  /src/bstat
> +/src/btrfs_ioctl_helper
>  /src/bulkstat_unlink_test
>  /src/bulkstat_unlink_test_modified
>  /src/dbtest
> diff --git a/common/btrfs b/common/btrfs
> new file mode 100644
> index 0000000..b972b13
> --- /dev/null
> +++ b/common/btrfs
> @@ -0,0 +1,43 @@
> +#!/bin/bash
> +# Functions for testing btrfs
> +
> +_btrfs_get_fsid()
> +{
> +	local mnt=$1
> +	if [ -z "$mnt" ]; then
> +		mnt=$TEST_DIR
> +	fi
> +	$BTRFS_UTIL_PROG filesystem show $mnt|awk '/uuid:/ {print $NF}'
> +}
> +
> +_btrfs_get_sysfs()
> +{
> +	local mnt=$1
> +	local fsid=$(_btrfs_get_fsid $mnt)
> +	echo "/sys/fs/btrfs/$fsid"
> +}
> +
> +_require_btrfs_sysfs()
> +{
> +	local mnt=$1
> +	if [ -z "$mnt" ]; then
> +		mnt=$TEST_DIR
> +	fi
> +	if [ ! -d "$(_btrfs_get_sysfs $mnt)" ];then
> +		_notrun "btrfs sysfs support not available."
> +	fi
> +}

I think this helper can be expended to accept an sysfs attribute and
test if the required attribute exists, and _notrun if not exist. So the
following piece of code can be omitted.

 +SYSFS_PREFIX="$(_btrfs_get_sysfs)/allocation"
 +[ -d "$SYSFS_PREFIX" ] || _notrun "sysfs directory not found"
 +

We can simply do "_require_btrfs_sysfs allocation" in the test.

> +_require_btrfs_ioctl()
> +{
> +	local ioctl=$1
> +	local mnt=$2
> +	shift 2
> +	if [ -z "$mnt" ]; then
> +		mnt=$TEST_DIR
> +	fi

Need a '_require_test_program "btrfs_ioctl_helper"' here to make sure
the binary is built.

> +	out=$(src/btrfs_ioctl_helper $mnt $ioctl $@)
> +	if [ "$out" = "Not implemented." ]; then
> +		_notrun "btrfs ioctl $ioctl not implemented."
> +	fi
> +}
> diff --git a/src/Makefile b/src/Makefile
> index 1bf318b..c467475 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -20,7 +20,8 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
>  	bulkstat_unlink_test_modified t_dir_offset t_futimens t_immutable \
>  	stale_handle pwrite_mmap_blocked t_dir_offset2 seek_sanity_test \
>  	seek_copy_test t_readdir_1 t_readdir_2 fsync-tester nsexec cloner \
> -	renameat2 t_getcwd e4compact test-nextquota punch-alternating
> +	renameat2 t_getcwd e4compact test-nextquota punch-alternating \
> +	btrfs_ioctl_helper
>  
>  SUBDIRS =
>  
> diff --git a/src/btrfs_ioctl_helper.c b/src/btrfs_ioctl_helper.c
> new file mode 100644
> index 0000000..b6eb924
> --- /dev/null
> +++ b/src/btrfs_ioctl_helper.c
> @@ -0,0 +1,132 @@
> +#include <sys/ioctl.h>
> +#include <stdio.h>
> +#include <sys/fcntl.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +
> +#ifndef BTRFS_IOCTL_MAGIC
> +#define BTRFS_IOCTL_MAGIC 0x94
> +#endif
> +
> +#ifndef BTRFS_IOC_SPACE_INFO
> +struct btrfs_ioctl_space_info {
> +        uint64_t flags;
> +        uint64_t total_bytes;
> +        uint64_t used_bytes;
> +};
> +
> +struct btrfs_ioctl_space_args {
> +        uint64_t space_slots;
> +        uint64_t total_spaces;
> +        struct btrfs_ioctl_space_info spaces[0];
> +};
> +#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
> +                                    struct btrfs_ioctl_space_args)
> +#endif
> +#ifndef BTRFS_SPACE_INFO_GLOBAL_RSV
> +#define BTRFS_SPACE_INFO_GLOBAL_RSV    (1ULL << 49)
> +#endif
> +
> +static int global_rsv_ioctl(int fd, int argc, char *argv[])
> +{
> +	struct btrfs_ioctl_space_args arg;
> +	struct btrfs_ioctl_space_args *args;
> +	int ret;
> +	int i;
> +	size_t size;
> +
> +	arg.space_slots = 0;
> +
> +	ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, &arg);
> +	if (ret)
> +		return -errno;
> +
> +	size = sizeof(*args) + sizeof(args->spaces[0]) * arg.total_spaces;
> +	args = malloc(size);
> +	if (!args)
> +		return -ENOMEM;
> +
> +	args->space_slots = arg.total_spaces;
> +
> +	ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, args);
> +	if (ret)
> +		return -errno;
> +
> +	for (i = 0; i < args->total_spaces; i++) {
> +		if (args->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) {
> +			unsigned long long reserved;
> +			reserved = args->spaces[i].total_bytes;
> +			printf("%llu\n", reserved);
> +			return 0;
> +		}
> +	}
> +
> +	return -ENOENT;
> +}
> +
> +#define IOCTL_TABLE_ENTRY(_ioctl_name, _handler) \
> +	{ .name = #_ioctl_name, .ioctl_cmd = BTRFS_IOC_##_ioctl_name, \
> +	  .handler = _handler, }
> +
> +struct ioctl_table_entry {
> +	const char *name;
> +	unsigned ioctl_cmd;
> +	int (*handler)(int fd, int argc, char *argv[]);
> +};
> +
> +static struct ioctl_table_entry ioctls[] = {
> +	IOCTL_TABLE_ENTRY(SPACE_INFO, global_rsv_ioctl),
> +};
> +
> +int
> +main(int argc, char *argv[])
> +{
> +	int fd;
> +	int ret;
> +	struct ioctl_table_entry *entry = NULL;
> +	int i;
> +
> +	if (argc < 3) {
> +		fprintf(stderr,
> +			"usage: %s <fs mount point> <ioctl name> [args..]\n",
> +			argv[0]);
> +		return 1;
> +	}
> +
> +	fd = open(argv[1], O_RDONLY|O_DIRECTORY);
> +	if (fd < 0) {
> +		perror(argv[1]);
> +		return 1;
> +	}
> +
> +	for (i = 0; i < (sizeof(ioctls)/sizeof(ioctls[0])); i++) {
> +		if (strcmp(argv[2], ioctls[i].name) == 0) {
> +			entry = &ioctls[i];
> +			break;
> +		}
> +	}
> +
> +	if (!entry) {
> +		fprintf(stderr, "ERROR: unknown ioctl %s\n", argv[2]);
> +		close(fd);
> +		return 1;
> +	}
> +
> +	ret = entry->handler(fd, argc - 3, argv + 3);
> +	if (ret == -ENOTTY) {
> +		printf("Not implemented.\n");
> +		close(fd);
> +		return 0;
> +	} else if (ret) {
> +		fprintf(stderr, "ERROR: %s failed: %s\n",
> +			entry->name, strerror(-ret));
> +		close(fd);
> +		return 1;
> +	}
> +
> +	close(fd);
> +	return 0;
> +}
> diff --git a/tests/btrfs/124 b/tests/btrfs/124
> new file mode 100755
> index 0000000..2ab9dfb
> --- /dev/null
> +++ b/tests/btrfs/124
> @@ -0,0 +1,84 @@
> +#!/bin/bash
> +# FA QA Test No. 124
> +#
> +# Test global metadata reservation reporting
> +#
> +# 1) Create empty file system
> +# 2) Call the BTRFS_IOC_GLOBAL_RSV ioctl
> +# 3) Read the /sys/fs/btrfs/<fsid>/allocation/global_rsv_reserved file
> +#    and confirm it's a number
> +# 4) Compare the results between the two to confirm they match
> +#
> +#-----------------------------------------------------------------------
> +# Copyright (c) 2016 SUSE, All Rights Reserved.
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it would be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write the Free Software Foundation,
> +# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  12110-1301  USA
> +#-----------------------------------------------------------------------
> +
> +seq=$(basename $0)
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=$(pwd)
> +tmp=/tmp/$$
> +status=1
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/btrfs
> +. ./common/filter.btrfs
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +_supported_fs btrfs
> +_supported_os Linux
> +_require_test
> +_require_btrfs_ioctl SPACE_INFO
> +_require_btrfs_sysfs
> +
> +IOCTL="src/btrfs_ioctl_helper"
> +
> +SYSFS_PREFIX="$(_btrfs_get_sysfs)/allocation"

We usually use lowercase names for local use in fstests, reserve
uppercase names for global names like SCRATCH_DEV, MOUNT_PROG

> +[ -d "$SYSFS_PREFIX" ] || _notrun "sysfs directory not found"
> +
> +check_sysfs_output()
> +{
> +	reserved="$1"
> +	method="$2"
> +	if [ -n "$(echo $reserved | tr -d 0-9)" ]; then
> +		echo "$method: numerical value expected (got $reserved)"
> +	fi
> +}
> +
> +ioctl_reserved="$($IOCTL $TEST_DIR SPACE_INFO)"
> +
> +reserved="$(cat $SYSFS_PREFIX/global_rsv_reserved)"
> +check_sysfs_output "$reserved" "sysfs:reserved"
> +if [ "$reserved" != "$ioctl_reserved" ]; then
> +	echo "ioctl ($ioctl_reserved) != sysfs ($reserved)"
> +fi
> +size="$(cat $SYSFS_PREFIX/global_rsv_size)"
> +check_sysfs_output "$size" "sysfs:size"
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/btrfs/124.out b/tests/btrfs/124.out
> new file mode 100644
> index 0000000..0129e81
> --- /dev/null
> +++ b/tests/btrfs/124.out
> @@ -0,0 +1 @@
> +QA output created by 124

In fstests if the test doesn't print anything to stdout, some sentence
is needed to indicate the fact, usually it's "Silence is golden".

> diff --git a/tests/btrfs/group b/tests/btrfs/group
> index 5a26ed7..8b5050e 100644
> --- a/tests/btrfs/group
> +++ b/tests/btrfs/group
> @@ -126,3 +126,4 @@
>  121 auto quick snapshot qgroup
>  122 auto quick snapshot qgroup
>  123 auto quick qgroup
> +124 auto quick metadata
> -- 
> 1.8.5.6
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 3/4] btrfs/125: test sysfs exports of allocation and device membership info
  2016-06-27 20:14 ` [PATCH v2 3/4] btrfs/125: test sysfs exports of allocation and device membership info jeffm
@ 2016-06-30  4:41   ` Eryu Guan
  0 siblings, 0 replies; 10+ messages in thread
From: Eryu Guan @ 2016-06-30  4:41 UTC (permalink / raw)
  To: jeffm; +Cc: fstests, linux-btrfs

On Mon, Jun 27, 2016 at 04:14:13PM -0400, jeffm@suse.com wrote:
> From: Jeff Mahoney <jeffm@suse.com>
> 
> This tests the sysfs publishing for btrfs allocation and device
> membership info under a number of different layouts, similar to the
> btrfs replace test. We test the allocation files only for existence and
> that they contain numerical values. We test the device membership
> by mapping the devices used to create the file system to sysfs paths
> and matching them against the paths used for the device membership
> symlinks.
> 
> Signed-off-by: Jeff Mahoney <jeffm@suse.com>
> ---
>  common/btrfs        |   7 +++
>  common/config       |   7 ++-
>  tests/btrfs/125     | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/btrfs/125.out |   1 +
>  tests/btrfs/group   |   1 +
>  5 files changed, 190 insertions(+), 3 deletions(-)
>  create mode 100755 tests/btrfs/125
>  create mode 100644 tests/btrfs/125.out
> 
> diff --git a/common/btrfs b/common/btrfs
> index b972b13..5828d0a 100644
> --- a/common/btrfs
> +++ b/common/btrfs
> @@ -41,3 +41,10 @@ _require_btrfs_ioctl()
>  		_notrun "btrfs ioctl $ioctl not implemented."
>  	fi
>  }
> +
> +# Requires the minimum size pool for largest btrfs RAID test
> +_require_btrfs_raid_dev_pool()
> +{
> +	_require_scratch_dev_pool 4 # RAID10
> +	_require_scratch_dev_pool_equal_size
> +}

I don't think this helper is needed, calling the two _requires in the
test directly is good enough and clear.

> diff --git a/common/config b/common/config
> index c25b1ec..8577924 100644
> --- a/common/config
> +++ b/common/config
> @@ -201,13 +201,14 @@ export DEBUGFS_PROG="`set_prog_path debugfs`"
>  # newer systems have udevadm command but older systems like RHEL5 don't.
>  # But if neither one is available, just set it to "sleep 1" to wait for lv to
>  # be settled
> -UDEV_SETTLE_PROG="`set_prog_path udevadm`"
> -if [ "$UDEV_SETTLE_PROG" == "" ]; then
> +UDEVADM_PROG="`set_prog_path udevadm`"
> +if [ "$UDEVADM_PROG" == "" ]; then
>  	# try udevsettle command
>  	UDEV_SETTLE_PROG="`set_prog_path udevsettle`"
>  else
>  	# udevadm is available, add 'settle' as subcommand
> -	UDEV_SETTLE_PROG="$UDEV_SETTLE_PROG settle"
> +	UDEV_SETTLE_PROG="$UDEVADM_PROG settle"
> +	export UDEVADM_PROG

UDEVADM_PROG should be exported no matter it's empty or not.

>  fi
>  # neither command is available, use sleep 1
>  if [ "$UDEV_SETTLE_PROG" == "" ]; then
> diff --git a/tests/btrfs/125 b/tests/btrfs/125
> new file mode 100755
> index 0000000..999a10e
> --- /dev/null
> +++ b/tests/btrfs/125
> @@ -0,0 +1,177 @@
> +#! /bin/bash
> +# FS QA Test No. 125
> +#
> +# Test of the btrfs sysfs publishing
> +#
> +#-----------------------------------------------------------------------
> +# Copyright (C) 2016 SUSE.  All rights reserved.
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it would be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write the Free Software Foundation,
> +# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> +#
> +#-----------------------------------------------------------------------
> +#
> +
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1
> +
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/btrfs
> +. ./common/filter
> +
> +# real QA test starts here
> +_supported_fs btrfs
> +_supported_os Linux
> +_require_scratch
> +_require_command "$UDEVADM_PROG" udevadm
> +_require_test
> +_require_btrfs_sysfs
> +_require_btrfs_raid_dev_pool
> +
> +sysfs_root=$(_btrfs_get_sysfs $TEST_DIR)
> +
> +[ -d "$sysfs_root/allocation" ] || _notrun "sysfs allocation dir not found"
> +[ -d "$sysfs_root/devices" ] || _notrun "sysfs devices dir not found"

With _require_btrfs_sysfs updated, we can just call

_require_btrfs_sysfs allocation
_require_btrfs_sysfs devices

> +
> +check_file()
> +{
> +	local file=$1
> +	base="$(basename $(dirname $file))/$(basename $file)"
> +	value="$(cat $file)"
> +	if [ -n "$(echo $value | tr -d 0-9)" ]; then
> +		echo "ERROR: $base: numerical value expected" \
> +		     "(got $value)"
> +	fi
> +}
> +
> +check_chunk()
> +{
> +	path=$1
> +	mkfs_options=$2
> +
> +	chunktype=$(basename $path)
> +	[ -d "$path" ] || echo "No $chunktype directory."
> +
> +	for file in bytes_may_use bytes_pinned bytes_reserved bytes_used \
> +		    disk_total disk_used flags total_bytes \
> +		    total_bytes_pinned; do
> +		check_file "$path/$file"
> +	done
> +
> +	if [ "$chunktype" = "data" -o "$chunktype" = "mixed" ]; then
> +		opt="-d"
> +	elif [ "$chunktype" = "metadata" -o "$chunktype" = "system" ]; then
> +		opt="-m"
> +	fi
> +
> +	profile=$(echo $mkfs_options | sed -e "s/.*$opt \([[:alnum:]]*\).*/\1/")
> +	[ -d "$path/$profile" ] || echo "No $profile dir for $chunktype"
> +
> +	for file in total_bytes used_bytes; do
> +		check_file $path/$profile/$file
> +	done
> +}
> +
> +check_dev_link()
> +{
> +	local dev=$1
> +	DEV="/sys/$($UDEVADM_PROG info --query=path $dev)"
> +	DEV="$(readlink -f $DEV)"

lowercase local names

> +	found=false
> +	for link in $sysfs_base/devices/*; do
> +		LINK="$(readlink -f $link)"
> +		if [ "$LINK" = "$DEV" ]; then
> +			found=true
> +			break
> +		fi
> +	done
> +	if ! $found; then
> +		echo "Symlink for $dev missing in $sysfs_base/devices"
> +	fi
> +	return 0
> +}
> +
> +workout()
> +{
> +	local mkfs_options="$1"
> +	local num_devs4raid="$2"
> +	local fssize
> +	local used_devs=""
> +
> +	if [ "$num_devs4raid" -gt 1 ]; then
> +		used_devs=$(echo $SCRATCH_DEV_POOL|tr '\t' ' '| \
> +			    cut -d ' ' -f 2-$num_devs4raid)
> +	fi
> +
> +	# We check the error code since mkfs can fail if the devices
> +	# are specified incorrectly but we may still have a file system
> +	# from a prior run.
> +	_scratch_mkfs $mkfs_options $used_devs 2>> $seqres.full || \
> +		_fail "mkfs failed"

Ah, I got it wrong about _scratch_mkfs previously, SCRATCH_DEV was cut
off from $used_devs, so _scratch_mkfs works here. It's not obvious,
would be better to have some comments here.

Thanks,
Eryu

> +
> +	_scratch_mount
> +
> +	# Check allocation
> +	sysfs_base="$(_btrfs_get_sysfs $SCRATCH_MNT)"
> +
> +	mixed=false
> +	case "$mkfs_options" in
> +	*-M*)
> +		mixed=true;
> +		;;
> +	esac
> +
> +	check_chunk "$sysfs_base/allocation/system" "$mkfs_options"
> +	if $mixed; then
> +		check_chunk "$sysfs_base/allocation/mixed" "$mkfs_options"
> +	else
> +		check_chunk "$sysfs_base/allocation/data" "$mkfs_options"
> +		check_chunk "$sysfs_base/allocation/metadata" "$mkfs_options"
> +	fi
> +
> +	for dev in $used_devs; do
> +		check_dev_link $dev
> +	done
> +
> +	_scratch_unmount
> +}
> +
> +workout "-m single -d single" 1
> +workout "-m single -d single -M" 1
> +workout "-m dup -d single" 1
> +workout "-m dup -d dup -M" 1
> +workout "-m raid0 -d raid0" 2
> +workout "-m raid1 -d raid1" 2
> +workout "-m raid5 -d raid5" 2
> +workout "-m raid6 -d raid6" 3
> +workout "-m raid10 -d raid10" 4
> +
> +status=0
> +exit
> diff --git a/tests/btrfs/125.out b/tests/btrfs/125.out
> new file mode 100644
> index 0000000..4f22ab0
> --- /dev/null
> +++ b/tests/btrfs/125.out
> @@ -0,0 +1 @@
> +QA output created by 125
> diff --git a/tests/btrfs/group b/tests/btrfs/group
> index 8b5050e..3535f02 100644
> --- a/tests/btrfs/group
> +++ b/tests/btrfs/group
> @@ -127,3 +127,4 @@
>  122 auto quick snapshot qgroup
>  123 auto quick qgroup
>  124 auto quick metadata
> +125 auto quick metadata
> -- 
> 1.8.5.6
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 4/4] btrfs/126,127,128: test feature ioctl and sysfs interfaces
  2016-06-27 20:14 ` [PATCH v2 4/4] btrfs/126,127,128: test feature ioctl and sysfs interfaces jeffm
@ 2016-06-30  6:30   ` Eryu Guan
  0 siblings, 0 replies; 10+ messages in thread
From: Eryu Guan @ 2016-06-30  6:30 UTC (permalink / raw)
  To: jeffm; +Cc: fstests, linux-btrfs

On Mon, Jun 27, 2016 at 04:14:14PM -0400, jeffm@suse.com wrote:
> From: Jeff Mahoney <jeffm@suse.com>
> 
> This tests the exporting of feature information from the kernel via
> sysfs and ioctl. The first test works whether the sysfs permissions
> are correct, if the information exported via sysfs matches
> what the ioctls are reporting, and if they both match the on-disk
> superblock's version of the feature sets. The second and third tests
> test online setting and clearing of feature bits via the sysfs and
> ioctl interfaces, checking whether they match the on-disk super on
> each cycle.

Theses tests passed for me with 4.7-rc5 kernel & v4.6 btrfs-progs
(x86_64 and ppc64 host), as well as RHEL7 kernel & btrfs-progs.

Some minor issues inline.

> 
> Signed-off-by: Jeff Mahoney <jeffm@suse.com>
> ---
>  common/btrfs             | 203 +++++++++++++++++++++++++++++++++++++++
>  src/btrfs_ioctl_helper.c |  88 +++++++++++++++++
>  tests/btrfs/126          | 244 +++++++++++++++++++++++++++++++++++++++++++++++
>  tests/btrfs/126.out      |   1 +
>  tests/btrfs/127          | 166 ++++++++++++++++++++++++++++++++
>  tests/btrfs/127.out      |   1 +
>  tests/btrfs/128          | 128 +++++++++++++++++++++++++
>  tests/btrfs/128.out      |   1 +
>  tests/btrfs/group        |   3 +
>  9 files changed, 835 insertions(+)
>  create mode 100755 tests/btrfs/126
>  create mode 100644 tests/btrfs/126.out
>  create mode 100755 tests/btrfs/127
>  create mode 100644 tests/btrfs/127.out
>  create mode 100755 tests/btrfs/128
>  create mode 100644 tests/btrfs/128.out
> 
> diff --git a/common/btrfs b/common/btrfs
> index 5828d0a..2d7d0ce 100644
> --- a/common/btrfs
> +++ b/common/btrfs
> @@ -48,3 +48,206 @@ _require_btrfs_raid_dev_pool()
>  	_require_scratch_dev_pool 4 # RAID10
>  	_require_scratch_dev_pool_equal_size
>  }
> +
> +# TODO Add tool to enable and test unknown feature bits
> +_btrfs_feature_lookup() {
> +	local name=$1
> +	class=""
> +	case "$name" in
> +	mixed_backref)	class=incompat; bit=0x1 ;;
> +	default_subvol)	class=incompat; bit=0x2 ;;
> +	mixed_groups)	class=incompat; bit=0x4 ;;
> +	compress_lzo)	class=incompat; bit=0x8 ;;
> +	compress_lsov2)	class=incompat; bit=0x10 ;;
> +	big_metadata)	class=incompat; bit=0x20 ;;
> +	extended_iref)	class=incompat; bit=0x40 ;;
> +	raid56)		class=incompat; bit=0x80 ;;
> +	skinny_metadata)class=incompat; bit=0x100 ;;
> +	compat:*)	class=compat; bit=${name##compat:} ;;
> +	compat_ro:*)	class=compat_ro; bit=${name##compat_ro:} ;;
> +	incompat:*)	class=incompat; bit=${name##incompat:} ;;
> +	esac
> +	if [ -z "$class" ]; then
> +		echo "Unknown feature name $name. xfstests needs updating." \
> +		     " Skipping the test of sysfs values to superblock values" \
> +		     >&2
> +	fi
> +
> +	echo "$class/$bit"
> +}
> +
> +_btrfs_feature_get_class() {
> +	bits=$(_btrfs_feature_lookup $1)
> +	echo ${bits%/*}
> +}
> +
> +_btrfs_feature_get_bit() {
> +	bits=$(_btrfs_feature_lookup $1)
> +	echo ${bits#*/}
> +}
> +
> +_btrfs_feature_class_to_index()
> +{
> +	local class=$1
> +	local index=0
> +
> +	case "$class" in
> +	compat) index=0 ;;
> +	compat_ro) index=1 ;;
> +	incompat) index=2 ;;
> +	*) echo "Invalid class name $class" >&2
> +	esac
> +
> +	echo $index
> +}
> +
> +# The ioctl helper outputs the supported feature flags as a series of
> +# 9 hex numbers, which represent bitfields.
> +# These 9 values represent 3 sets of 3 values.
> +# supported flags: compat compat_ro incompat, starting at index 0
> +# settable online: compat compat_ro incompat, starting at index 3
> +# clearable online: compat compat_ro incompat, starting at index 6
> +# The returned mask is: 0x1 settable | 0x2 clearable
> +_btrfs_feature_ioctl_writeable_mask()
> +{
> +	local feature=$1
> +	local mnt=$2
> +	local index=0
> +
> +	# This usually won't matter.  The supported bits are fs-module global.
> +	if [ -z "$mnt" ]; then
> +		mnt=$TEST_DIR
> +	fi
> +
> +	class=$(_btrfs_feature_get_class $1)
> +	bit=$(_btrfs_feature_get_bit $1)
> +	index=$(_btrfs_feature_class_to_index $class)
> +
> +	local set_index=$(( $index + 3 ))
> +	local clear_index=$(( $index + 6 ))
> +
> +	out=$(src/btrfs_ioctl_helper $mnt GET_SUPPORTED_FEATURES)
> +	set -- $out
> +	supp_features=($@)
> +
> +	settable=$(( ${supp_features[$set_index]} & $bit ))
> +	clearable=$(( ${supp_features[$clear_index]} & $bit ))
> +
> +	val=0

I noticed that some of the variables in the helper are not declared as
'local' and in the tests there're the same vars like val, class, out.
It's better and safe to make all vars in helpers as 'local'.

> +	if [ "$settable" -ne 0 ]; then
> +		val=$(( $val | 1 ))
> +	fi
> +	if [ "$clearable" -ne 0 ]; then
> +		val=$(( $val | 2 ))
> +	fi
> +
> +	echo $val
> +}
> +
> +_btrfs_feature_ioctl_index_settable_mask()
> +{
> +	local class_index=$1
> +	local mnt=$2
> +
> +	# This usually won't matter.  The supported bits are fs-module global.
> +	if [ -z "$mnt" ]; then
> +		mnt=$TEST_DIR
> +	fi
> +
> +	local set_index=$(( $class_index + 3 ))
> +
> +	out=$(src/btrfs_ioctl_helper $mnt GET_SUPPORTED_FEATURES)
> +	set -- $out
> +	supp_features=($@)
> +
> +	echo $(( ${supp_features[$set_index]} ))
> +}
> +
> +_btrfs_feature_ioctl_index_clearable_mask()
> +{
> +	local class_index=$1
> +	local mnt=$2
> +	local index=0
> +
> +	# This usually won't matter.  The supported bits are fs-module global.
> +	if [ -z "$mnt" ]; then
> +		mnt=$TEST_DIR
> +	fi
> +
> +	local set_index=$(( $class_index + 6 ))
> +
> +	out=$(src/btrfs_ioctl_helper $mnt GET_SUPPORTED_FEATURES)
> +	set -- $out
> +	supp_features=($@)
> +
> +	echo $(( ${supp_features[$clear_index]} ))
> +}
> +
> +_btrfs_feature_ioctl_is_writeable()
> +{
> +	local feature=$1
> +	local mnt=$2
> +	local mask=$(_btrfs_feature_ioctl_writeable_mask $feature $2)
> +
> +	test "$mask" -ne 0
> +	return $?
> +}
> +
> +_btrfs_feature_ioctl_is_settable()
> +{
> +	local feature=$1
> +	local mnt=$2
> +	local mask=$(_btrfs_feature_ioctl_writeable_mask $feature $2)
> +
> +	if [ "$(( $mask & 1 ))" -ne 0 ]; then
> +		echo "true"
> +	else
> +		echo "false"
> +	fi
> +}
> +
> +_btrfs_feature_ioctl_is_settable()
> +{
> +	local feature=$1
> +	local mnt=$2
> +	local mask=$(_btrfs_feature_ioctl_writeable_mask $feature $2)
> +
> +	if [ "$(( $mask & 2 ))" -ne 0 ]; then
> +		echo "true"
> +	else
> +		echo "false"
> +	fi
> +}
> +
> +_btrfs_feature_sysfs_is_settable()
> +{
> +	local feature=$1
> +
> +	val=$(cat /sys/fs/btrfs/features/$feature)
> +
> +	if [ "$(( $val & 2 ))" -eq 2 ]; then
> +		echo "true"
> +	else
> +		echo "false"
> +	fi
> +}
> +
> +_btrfs_feature_sysfs_is_clearable()
> +{
> +	local feature=$1
> +
> +	val=$(cat /sys/fs/btrfs/features/$feature)
> +
> +	if [ "$(( $val & 2 ))" -eq 2 ]; then
> +		echo "true"
> +	else
> +		echo "false"
> +	fi
> +}
> +
> +_btrfs_feature_disk_get_flags()
> +{
> +	local dev=$1
> +	local class=$2
> +	$BTRFS_SHOW_SUPER_PROG $dev | grep ^${class}_flags | awk '{print $NF}'
> +}
> diff --git a/src/btrfs_ioctl_helper.c b/src/btrfs_ioctl_helper.c
> index b6eb924..4344bdc 100644
> --- a/src/btrfs_ioctl_helper.c
> +++ b/src/btrfs_ioctl_helper.c
> @@ -30,6 +30,21 @@ struct btrfs_ioctl_space_args {
>  #define BTRFS_SPACE_INFO_GLOBAL_RSV    (1ULL << 49)
>  #endif
>  
> +#ifndef BTRFS_IOC_GET_FEATURES
> +struct btrfs_ioctl_feature_flags {
> +	uint64_t compat_flags;
> +	uint64_t compat_ro_flags;
> +	uint64_t incompat_flags;
> +};
> +
> +#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
> +                                   struct btrfs_ioctl_feature_flags)
> +#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \
> +                                   struct btrfs_ioctl_feature_flags[2])
> +#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
> +                                   struct btrfs_ioctl_feature_flags[3])
> +#endif
> +
>  static int global_rsv_ioctl(int fd, int argc, char *argv[])
>  {
>  	struct btrfs_ioctl_space_args arg;
> @@ -67,6 +82,76 @@ static int global_rsv_ioctl(int fd, int argc, char *argv[])
>  	return -ENOENT;
>  }
>  
> +static int get_features_ioctl(int fd, int argc, char *argv[])
> +{
> +	struct btrfs_ioctl_feature_flags flags;
> +	int ret = ioctl(fd, BTRFS_IOC_GET_FEATURES, &flags);
> +	if (ret)
> +		return -errno;
> +
> +	printf("0x%llx 0x%llx 0x%llx\n",
> +	       (unsigned long long)flags.compat_flags,
> +	       (unsigned long long)flags.compat_ro_flags,
> +	       (unsigned long long)flags.incompat_flags);
> +	return 0;
> +}
> +
> +static int set_features_ioctl(int fd, int argc, char *argv[])
> +{
> +	struct btrfs_ioctl_feature_flags flags[2];
> +	uint64_t bit, *bits, *mask;
> +	if (argc != 3)
> +		goto usage;
> +
> +	memset(flags, 0, sizeof(flags));
> +
> +	errno = 0;
> +	bit = strtoull(argv[2], NULL, 10);
> +	if (errno)
> +		goto usage;
> +
> +	if (strcmp(argv[1], "compat") == 0) {
> +		mask = &flags[0].compat_flags;
> +		bits = &flags[1].compat_flags;
> +	} else if (strcmp(argv[1], "compat_ro") == 0) {
> +		mask = &flags[0].compat_ro_flags;
> +		bits = &flags[1].compat_ro_flags;
> +	} else if (strcmp(argv[1], "incompat") == 0) {
> +		mask = &flags[0].incompat_flags;
> +		bits = &flags[1].incompat_flags;
> +	} else
> +		goto usage;
> +
> +	*mask |= bit;
> +
> +	if (strcmp(argv[0], "set") == 0)
> +		*bits |= bit;
> +
> +	return ioctl(fd, BTRFS_IOC_SET_FEATURES, &flags);
> +usage:
> +	fprintf(stderr, "usage: SET_FEATURES <set|clear> <compat|compat_ro|incompat> <base-10 bitmask>\n");
> +	return -EINVAL;
> +}
> +
> +static int get_supported_features_ioctl(int fd, int argc, char *argv[])
> +{
> +	struct btrfs_ioctl_feature_flags flags[3];
> +	int ret;
> +	int i;
> +
> +	ret = ioctl(fd, BTRFS_IOC_GET_SUPPORTED_FEATURES, &flags);
> +	if (ret)
> +		return -errno;
> +
> +	for (i = 0; i < 3; i++)
> +		printf("0x%llx 0x%llx 0x%llx ",
> +		       (unsigned long long)flags[i].compat_flags,
> +		       (unsigned long long)flags[i].compat_ro_flags,
> +		       (unsigned long long)flags[i].incompat_flags);
> +
> +	printf("\n");
> +	return 0;
> +}
>  #define IOCTL_TABLE_ENTRY(_ioctl_name, _handler) \
>  	{ .name = #_ioctl_name, .ioctl_cmd = BTRFS_IOC_##_ioctl_name, \
>  	  .handler = _handler, }
> @@ -79,6 +164,9 @@ struct ioctl_table_entry {
>  
>  static struct ioctl_table_entry ioctls[] = {
>  	IOCTL_TABLE_ENTRY(SPACE_INFO, global_rsv_ioctl),
> +	IOCTL_TABLE_ENTRY(GET_FEATURES, get_features_ioctl),
> +	IOCTL_TABLE_ENTRY(SET_FEATURES, set_features_ioctl),
> +	IOCTL_TABLE_ENTRY(GET_SUPPORTED_FEATURES, get_supported_features_ioctl),
>  };
>  
>  int
> diff --git a/tests/btrfs/126 b/tests/btrfs/126
> new file mode 100755
> index 0000000..71307a3
> --- /dev/null
> +++ b/tests/btrfs/126
> @@ -0,0 +1,244 @@
> +#!/bin/bash
> +# FA QA Test No. 126
> +#
> +# Test online feature publishing
> +#
> +# This test doesn't test the changing of features. It does test that
> +# the proper publishing bits and permissions match up with
> +# the expected values.
> +#
> +#-----------------------------------------------------------------------
> +# Copyright (c) 2016 SUSE, All Rights Reserved.
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it would be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write the Free Software Foundation,
> +# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> +#-----------------------------------------------------------------------
> +
> +seq=$(basename $0)
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=$(pwd)
> +tmp=/tmp/$$
> +status=1
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +        cd /
> +        rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/btrfs
> +. ./common/filter.btrfs
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +_supported_fs btrfs
> +_supported_os Linux
> +_require_scratch
> +_require_command "$BTRFS_SHOW_SUPER_PROG" btrfs-show-super
> +_require_test_program btrfs_ioctl_helper
> +_require_test
> +_require_btrfs_ioctl GET_FEATURES $TEST_DIR
> +_require_btrfs_ioctl GET_SUPPORTED_FEATURES $TEST_DIR
> +_require_btrfs_sysfs
> +
> +IOCTL="src/btrfs_ioctl_helper"
> +
> +sysfs_root="/sys/fs/btrfs"
> +[ -d "$sysfs_root/features" ] || _notrun "sysfs features dir not found"
> +[ -d "$(_btrfs_get_sysfs)/features" ] || _notrun "sysfs per-fs features dir not found"
> +
> +_scratch_mkfs 2>> $seqres.full
> +_scratch_mount
> +sysfs_fsroot=$(_btrfs_get_sysfs $SCRATCH_MNT)
> +
> +
> +# test -w will always return true if root is making the call.
> +# This would be true in most cases, but for sysfs files, the permissions
> +# are enforced even for root.
> +is_writeable()
> +{
> +	local file=$1
> +	mode=$(stat -c "0%a" "$file")
> +	mode=$(( $mode & 0200 ))
> +
> +	[ "$mode" -eq 0 ] && return 1
> +	return 0
> +}
> +
> +# Check enabled features in sysfs vs what the superblock claims
> +sysfs_features=(0 0 0)
> +
> +for file in $sysfs_fsroot/features/*; do
> +	feature=$(basename $file)
> +	supported=$(cat $sysfs_root/features/$feature)
> +
> +	case "$supported" in
> +	0|1|2|3) ;;
> +	*)
> +		echo "Invalid value $supported in features/$feature"
> +		continue
> +	esac
> +
> +	if [ ! -e "$sysfs_root/features/$feature" ]; then
> +		echo "fsid/features/$feature exists but features/$feature does not."
> +		continue
> +	fi
> +
> +	val=$(cat $file)
> +
> +	if [ -n "$(echo -n $supported| tr -d 0-9)" ]; then
> +		echo "features/$feature has invalid contents $supported"
> +		continue
> +	fi
> +	if [ -n "$(echo -n $val| tr -d 0-9)" ]; then
> +		echo "fsid/features/$feature has invalid contents $val"
> +		continue
> +	fi
> +	val=$(( $val ))
> +
> +	if [ "$supported" -eq 0 ]; then
> +		if is_writeable "$file"; then
> +			echo "fsid/features/$feature is writable but features/$feature has a 0 value."
> +		fi
> +
> +		if _btrfs_feature_ioctl_is_writeable $feature; then
> +			echo "fsid/features/$feature is not writeable but ioctl says it is"
> +		fi
> +	else
> +		if ! is_writeable "$file"; then
> +			echo "fsid/features/$feature is not writable but features/$feature has a nonzero value $val."
> +		fi
> +
> +		if ! _btrfs_feature_ioctl_is_writeable $feature; then
> +			echo "fsid/features/$feature is writeable but ioctl says it isn't"
> +		fi
> +	fi
> +
> +	bit=$(_btrfs_feature_get_bit $feature)
> +	class=$(_btrfs_feature_get_class $feature)
> +	if [ "$class" = "compat" ]; then
> +		sysfs_features[0]=$(( ${sysfs_features[0]} | $bit ))
> +	elif [ "$class" = "compat_ro" ]; then
> +		sysfs_features[1]=$(( ${sysfs_features[1]} | $bit ))
> +	elif [ "$class" = "incompat" ]; then
> +		sysfs_features[2]=$(( ${sysfs_features[2]} | $bit ))
> +	fi
> +done
> +
> +for file in $sysfs_root/features/*; do
> +	feature=$(basename $file)
> +	val=$(cat $file)
> +	if [ "$val" -gt 0 ]; then
> +		if [ ! -e "$sysfs_fsroot/features/$feature" ]; then
> +			echo "features/$feature has a nonzero value ($val)" \
> +			     "but fsid/features/$feature doesn't exist"
> +		fi
> +		if ! is_writeable "$sysfs_fsroot/features/$feature"; then
> +			echo "features/$feature has a nonzero value ($val)" \
> +			     "but fsid/features/$feature is not writable"
> +		fi
> +		if ! _btrfs_feature_ioctl_is_writeable $feature; then
> +			echo "features/$feature has a nonzero value ($val) " \
> +			     "but ioctl says it is not writeable."
> +		fi
> +
> +		ioctl_settable=$(_btrfs_feature_ioctl_is_settable $feature)
> +		sysfs_settable=$(_btrfs_feature_sysfs_is_settable $feature)
> +
> +		if $sysfs_settable && ! $ioctl_settable; then
> +			echo "features/$feature exports settable " \
> +			      "but ioctl does not"
> +		fi
> +		if ! $sysfs_settable && $ioctl_settable; then
> +			echo "features/$feature does not export settable " \
> +			      "but ioctl does"
> +		fi
> +
> +		ioctl_clearable=$(_btrfs_feature_ioctl_is_settable $feature)
> +		sysfs_clearable=$(_btrfs_feature_sysfs_is_settable $feature)
> +
> +		if $sysfs_clearable && ! $ioctl_clearable; then
> +			echo "features/$feature exports clearable " \
> +			      "but ioctl does not"
> +		fi
> +		if ! $sysfs_clearable && $ioctl_clearable; then
> +			echo "features/$feature does not export clearable " \
> +			      "but ioctl does"
> +		fi
> +		continue
> +	fi
> +
> +	# This is ok; The file system supports this feature but the mounted
> +	# file system doesn't enable it.
> +	[ -e "$sysfs_fsroot/features/$feature" ] || continue
> +
> +	if is_writeable "$sysfs_fsroot/features/$feature"; then
> +		echo "features/$feature has a zero value but" \
> +		     "fsid/features/$feature is writable."
> +	fi
> +
> +	if _btrfs_feature_ioctl_is_writeable $feature; then
> +		echo "$feature isn't writable but ioctl says it is"
> +	fi
> +done
> +
> +fields=("compat" "compat_ro" "incompat")
> +
> +check_ioctl_flags()
> +{
> +	local class=$1
> +	local flags=$(( $2 ))
> +	local disk_flags=$(( $3 ))
> +
> +	if [ "$flags" -ne "$disk_flags" ]; then
> +		echo "ioctl returned different $class flags" \
> +		     "($flags) than those contained in superblock" \
> +		     "($disk_flags)"
> +	fi
> +}
> +
> +check_sysfs_flags()
> +{
> +	local class=$1
> +	local sysfs_flags=$(( $2 ))
> +	local disk_flags=$(( $3 ))
> +
> +	if [ "$sysfs_flags" -ne "$disk_flags" ]; then
> +		echo "sysfs returned different $class" \
> +		     "flags ($flags) than those contained in" \
> +		     "superblock ($disk_flags)" >&2
> +	fi
> +}
> +
> +# ioctl
> +out=$($IOCTL $SCRATCH_MNT GET_FEATURES)
> +set -- $out
> +ioctl_features=($@)
> +
> +for index in $(seq 0 2); do
> +	class=${fields[$index]}
> +	disk_flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
> +	check_ioctl_flags "$class" "${ioctl_features[$index]}" "$disk_flags"
> +	check_sysfs_flags "$class" "${sysfs_features[$index]}" "$disk_flags"
> +done
> +
> +_scratch_unmount
> +
> +status=0
> +exit
> diff --git a/tests/btrfs/126.out b/tests/btrfs/126.out
> new file mode 100644
> index 0000000..f162d8b
> --- /dev/null
> +++ b/tests/btrfs/126.out
> @@ -0,0 +1 @@
> +QA output created by 126
> diff --git a/tests/btrfs/127 b/tests/btrfs/127
> new file mode 100755
> index 0000000..191beff
> --- /dev/null
> +++ b/tests/btrfs/127
> @@ -0,0 +1,166 @@
> +#!/bin/bash
> +# FA QA Test No. 127
> +#
> +# Test online feature changing via ioctl
> +#
> +#-----------------------------------------------------------------------
> +# Copyright (c) 2016 SUSE, All Rights Reserved.
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it would be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write the Free Software Foundation,
> +# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> +#-----------------------------------------------------------------------
> +
> +seq=$(basename $0)
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=$(pwd)
> +tmp=/tmp/$$
> +status=1
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +        cd /
> +        rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/btrfs
> +. ./common/filter.btrfs
> +
> +rm -f $seqres.full
> +
> +_supported_fs btrfs
> +_supported_os Linux
> +_require_scratch
> +_require_command "$BTRFS_SHOW_SUPER_PROG" btrfs-show-super
> +_require_test_program btrfs_ioctl_helper
> +
> +IOCTL=src/btrfs_ioctl_helper
> +
> +# 3 values, one for each each of the fields
> +update_features()
> +{
> +	local ioctl_values=$($IOCTL $SCRATCH_MNT GET_FEATURES)
> +	set -- $ioctl_values
> +	features=($@)
> +}
> +
> +test_set_feature()
> +{
> +	local field=$1
> +	local bits=$2
> +	local class=${fields[$field]}
> +	local old=${features[$field]}
> +	msg=$($IOCTL $SCRATCH_MNT SET_FEATURES set $class $bits)
> +	update_features
> +	local new=${features[$field]}
> +
> +	expected=$(( $old | $bits ))
> +	new=$(( $new ))
> +	if [ "$expected" -ne "$new" ]; then
> +		echo "Feature setting failed; Got $new, expected $expected"
> +		return 1
> +	fi
> +}
> +
> +test_clear_feature()
> +{
> +	local field=$1
> +	local bits=$2
> +	local class=${fields[$field]}
> +	local old=${features[$field]}
> +	msg=$($IOCTL $SCRATCH_MNT SET_FEATURES clear $class $bits)
> +	update_features
> +	local new="${features[$field]}"
> +
> +	expected=$(( $old & ~$bits ))
> +	new=$(( $new ))
> +	if [ "$expected" -ne "$new" ]; then
> +		echo "Feature clearing failed; Got $new, expected $expected"
> +	fi
> +	return 0
> +}
> +
> +fields=("compat" "compat_ro" "incompat")
> +
> +check_flags()
> +{
> +	local index=$1
> +	local expected=$(( $2 ))
> +	local class=${fields[$index]}
> +
> +	local disk_flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
> +
> +	disk_flags=$(( $disk_flags ))
> +
> +	if [ "$disk_flags" -ne "$expected" ]; then
> +		echo "mismatch: $disk_flags != $expected"
> +	fi
> +}
> +
> +_scratch_mkfs 2>> $seqres.full
> +_scratch_mount
> +
> +update_features
> +
> +
> +# Cycle through settable features.
> +# Set the feature
> +# Reload ioctl version and test against expected new value
> +# Unmount and test against expected new value
> +# Remount
> +did_set=false
> +
> +for field in $(seq 0 2); do
> +	fset="$(_btrfs_feature_ioctl_index_settable_mask $field)"
> +	[ -z "$fset" ] && break
> +	for n in $(seq 0 63); do
> +		old="${features[$field]}"
> +		v="$(( $fset & (1 << $n) ))"
> +		[ "$v" -eq 0 ] && continue
> +		test_set_feature $field $v
> +		_scratch_unmount
> +		expected="$(( $old | $v ))"
> +		check_flags "$field" "$expected"
> +		_scratch_mount
> +		did_set=true
> +	done
> +done
> +$did_set || echo "No online-settable features to test." >> $seqres.full
> +
> +# Repeat with clearing features
> +id_clear=false
> +for field in $(seq 0 2); do
> +	fclear="$(_btrfs_feature_ioctl_index_clearable_mask $field)"
> +	[ -z "$fclear" ] && break
> +	for n in $(seq 0 63); do
> +		v="$(( $fclear & (1 << $n) ))"
> +		[ "$v" -eq 0 ] && continue
> +
> +		test_clear_feature $field $v
> +		_scratch_unmount
> +		expected=$(( $old &~ $v ))
> +		check_flags $field $expected
> +		_scratch_mount
> +		did_clear=true
> +	done
> +done
> +$did_clear || echo "No online-clearable features to test." >> $seqres.full
> +
> +_scratch_unmount
> +
> +status=0
> +exit
> diff --git a/tests/btrfs/127.out b/tests/btrfs/127.out
> new file mode 100644
> index 0000000..09d2be1
> --- /dev/null
> +++ b/tests/btrfs/127.out
> @@ -0,0 +1 @@
> +QA output created by 127
> diff --git a/tests/btrfs/128 b/tests/btrfs/128
> new file mode 100755
> index 0000000..46160d9
> --- /dev/null
> +++ b/tests/btrfs/128
> @@ -0,0 +1,128 @@
> +#!/bin/bash
> +# FA QA Test No. 128
> +#
> +# Test online feature changing via sysfs
> +#
> +#-----------------------------------------------------------------------
> +# Copyright (c) 2016 SUSE, All Rights Reserved.
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it would be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write the Free Software Foundation,
> +# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> +#-----------------------------------------------------------------------
> +
> +seq=$(basename $0)
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=$(pwd)
> +tmp=/tmp/$$
> +status=1
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +        cd /
> +        rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/btrfs
> +. ./common/filter.btrfs
> +
> +rm -f $seqres.full
> +
> +_supported_fs btrfs
> +_supported_os Linux
> +_require_scratch
> +_require_command $BTRFS_SHOW_SUPER_PROG

_require_command "$BTRFS_SHOW_SUPER_PROG" btrfs-show-super

> +_require_test
> +_require_btrfs_sysfs
> +
> +sysfs_root="/sys/fs/btrfs"
> +[ -d "$sysfs_root/features" ] || _notrun "sysfs features dir not found"
> +sysfs_fsroot=$(_btrfs_get_sysfs)
> +[ -d "$sysfs_fsroot/features" ] || _notrun "sysfs per-fs features dir not found"
> +
> +check_flags() {

"{" in a new line

> +	local class=$1
> +	local expected=$(( $2 ))
> +	disk_flags="$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)"
> +	disk_flags=$(( $disk_flags ))
> +	if [ "$disk_flags" != "$expected" ]; then
> +		echo "mismatch: $disk_flags-$expected"
> +	fi
> +}
> +
> +_scratch_mkfs 2>> $seqres.full
> +fields=("compat" "compat_ro" "incompat")
> +sysfs_base="/sys/fs/btrfs"
> +settable=""
> +clearable=""
> +
> +# Gather up the features the kernel knows about
> +_scratch_mount
> +
> +sysfs_fsroot=$(_btrfs_get_sysfs $SCRATCH_MNT)
> +
> +for file in $sysfs_base/features/*; do
> +	feature=$(basename $file)
> +	val=$(cat $file)
> +	if [ "$(( $val & 0x1 ))" -eq 1 ]; then
> +		settable="$settable $feature"
> +	fi
> +	if [ "$(( $val & 0x2 ))" -eq 2 ]; then
> +		clearable="$clearable $feature"
> +	fi
> +done
> +_scratch_unmount
> +
> +did_set=false
> +for feature in $settable; do
> +	class=$(_btrfs_feature_get_class $feature)
> +	bit=$(_btrfs_feature_get_bit $feature)
> +	flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
> +	flags=$(( $flags ))
> +	_scratch_mount
> +	val=$(cat $sysfs_fsroot/features/$feature)
> +	echo 1 > $sysfs_fsroot/features/$feature
> +	newval=$(cat $sysfs_fsroot/features/$feature)
> +	[ "$newval" -ne 1 ] && echo "Setting feature $feature failed"
> +	_scratch_unmount
> +	check_flags $class $(( $flags | $bit ))
> +	did_set=true
> +done
> +$did_set || echo "No online-settable features to test." >> $seqres.full
> +
> +did_clear=false
> +for feature in $clearable; do
> +	class=$(_btrfs_feature_get_class $feature)
> +	bit=$(_btrfs_feature_get_bit $feature)
> +	flags=$(_btrfs_feature_disk_get_flags $SCRATCH_DEV $class)
> +	flags=$(( $flags ))
> +
> +	_scratch_mount
> +	val=$(cat $sysfs_fsroot/features/$feature)
> +	[ "$val" -ne 1 ] && continue
> +	echo 0 > $sysfs_fsroot/features/$feature
> +	newval=$(cat $sysfs_fsroot/features/$feature)
> +	[ "$newval" -ne 0 ] && echo "Clearing feature $feature was ignored."
> +	_scratch_unmount
> +	check_flags $class $(( $flags & ~$bit ))
> +	did_clear=true
> +done
> +$did_clear || echo "No online-clearable features to test." >> $seqres.full
> +
> +# Still unmounted from set/clear tests

Just FYI, SCRATCH_DEV doesn't have to be unmounted after the test, the
test harness will do it anyway (and do fsck and check dmesg for WARNINGs
etc.).

> +status=0
> +exit
> diff --git a/tests/btrfs/128.out b/tests/btrfs/128.out
> new file mode 100644
> index 0000000..34f24a3
> --- /dev/null
> +++ b/tests/btrfs/128.out
> @@ -0,0 +1 @@
> +QA output created by 128
> diff --git a/tests/btrfs/group b/tests/btrfs/group
> index 3535f02..e76265d 100644
> --- a/tests/btrfs/group
> +++ b/tests/btrfs/group
> @@ -128,3 +128,6 @@
>  123 auto quick qgroup
>  124 auto quick metadata
>  125 auto quick metadata
> +126 auto quick metadata
> +127 auto quick metadata
> +128 auto quick metadata
> -- 
> 1.8.5.6
> 
> --
> To unsubscribe from this list: send the line "unsubscribe fstests" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-06-30  6:42 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-27 20:14 [PATCH v2 0/4] btrfs feature testing + props fix jeffm
2016-06-27 20:14 ` [PATCH v2 1/4] btrfs/048: extend _filter_btrfs_prop_error to handle additional errors jeffm
2016-06-29 13:48   ` Eryu Guan
2016-06-27 20:14 ` [PATCH v2 2/4] btrfs/124: test global metadata reservation reporting jeffm
2016-06-30  4:07   ` Eryu Guan
2016-06-27 20:14 ` [PATCH v2 3/4] btrfs/125: test sysfs exports of allocation and device membership info jeffm
2016-06-30  4:41   ` Eryu Guan
2016-06-27 20:14 ` [PATCH v2 4/4] btrfs/126,127,128: test feature ioctl and sysfs interfaces jeffm
2016-06-30  6:30   ` Eryu Guan
2016-06-28  8:34 ` [PATCH v2 0/4] btrfs feature testing + props fix Eryu Guan

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.