All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property
@ 2021-12-17 18:47 Goffredo Baroncelli
  2021-12-17 18:47 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Goffredo Baroncelli @ 2021-12-17 18:47 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
	Goffredo Baroncelli

From: Goffredo Baroncelli <kreijack@inwind.it>

This patches set is the userspace portion of the serie
"[PATCH V9] btrfs: allocation_hint mode".

Look this patches set for further information.

G.Baroncelli

Goffredo Baroncelli (2):
  btrfs-progs: new "allocation_hint" property.
  Update man page for allocator_hint property.

 Documentation/btrfs-property.asciidoc |  17 +++
 cmds/property.c                       | 204 ++++++++++++++++++++++++++
 kernel-shared/ctree.h                 |  13 ++
 3 files changed, 234 insertions(+)

-- 
2.34.1


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

* [PATCH 1/2] btrfs-progs: new "allocation_hint" property.
  2021-12-17 18:47 [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
@ 2021-12-17 18:47 ` Goffredo Baroncelli
  2022-01-05  2:29   ` Boris Burkov
  2021-12-17 18:47 ` [PATCH 2/2] Update man page for allocator_hint property Goffredo Baroncelli
  2021-12-17 18:53 ` Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property] Goffredo Baroncelli
  2 siblings, 1 reply; 8+ messages in thread
From: Goffredo Baroncelli @ 2021-12-17 18:47 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
	Goffredo Baroncelli

From: Goffredo Baroncelli <kreijack@inwind.it>

Handle the property allocation_hint of a btrfs device. Below
an example of use:

$ # set a new value
$ sudo btrfs property set /dev/vde allocation_hint DATA_ONLY

$ # get the current value
$ sudo btrfs property get /dev/vde allocation_hint
devid=4, path=/dev/vde: allocation_hint=DATA_ONLY

The following values are availables:
- DATA_ONLY
- PREFERRED_DATA (default)
- PREFERRED_METADATA
- METADATA_ONLY

Root privileges are required.

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds/property.c       | 204 ++++++++++++++++++++++++++++++++++++++++++
 kernel-shared/ctree.h |  13 +++
 2 files changed, 217 insertions(+)

diff --git a/cmds/property.c b/cmds/property.c
index 59ef997c..e6a38ee1 100644
--- a/cmds/property.c
+++ b/cmds/property.c
@@ -22,6 +22,7 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/xattr.h>
+#include <sys/sysmacros.h>
 #include <uuid/uuid.h>
 #include <btrfsutil.h>
 #include "cmds/commands.h"
@@ -30,6 +31,7 @@
 #include "common/open-utils.h"
 #include "common/utils.h"
 #include "common/help.h"
+#include "common/path-utils.h"
 
 #define XATTR_BTRFS_PREFIX     "btrfs."
 #define XATTR_BTRFS_PREFIX_LEN (sizeof(XATTR_BTRFS_PREFIX) - 1)
@@ -232,6 +234,202 @@ out:
 	return ret;
 }
 
+static int btrfs_find_devid_and_mnt(const char *devpath, int *devid,
+				    char *path, int maxpath)
+{
+	int ret, i, fd;
+	DIR *dir;
+	struct stat stdevpath;
+	struct btrfs_ioctl_fs_info_args fi_args;
+	struct btrfs_ioctl_dev_info_args dev_info;
+
+	ret = get_btrfs_mount(devpath, path, maxpath);
+	if (ret)
+		return ret;
+
+	fd = btrfs_open_dir(path, &dir, 1);
+	if (fd < 0)
+		return fd;
+
+	ret = stat(devpath, &stdevpath);
+	if (ret) {
+		error("cannot stat '%s'", devpath);
+		goto out;
+	}
+
+	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
+	if (ret < 0) {
+		if (errno == EPERM)
+			return -errno;
+		error("cannot get filesystem info: %m");
+		ret = -10;
+		goto out;
+	}
+
+	for (i = 0 ; i <= fi_args.max_id ; i++) {
+		struct stat st;
+
+		memset(&dev_info, 0, sizeof(dev_info));
+		ret = get_device_info(fd, i, &dev_info);
+		if (ret == -ENODEV)
+			continue;
+		if (ret) {
+			error("cannot get info about device devid=%d", i);
+			goto out;
+		}
+
+		if (!dev_info.path)
+			/* missing devices */
+			continue;
+
+		ret = stat((char *)dev_info.path, &st);
+		if (ret) {
+			error("cannot stat '%s'", devpath);
+			goto out;
+		}
+
+		if (major(st.st_rdev) == major(stdevpath.st_rdev) &&
+		    minor(st.st_rdev) == minor(stdevpath.st_rdev)) {
+			*devid = dev_info.devid;
+			ret = 0;
+			goto out;
+		}
+	}
+
+	ret = -12;
+
+out:
+	close_file_or_dir(fd, dir);
+	return ret;
+}
+
+static struct ull_charp_pair_t {
+	u64		value;
+	const char	*descr;
+} allocation_hint_description[] = {
+	{BTRFS_DEV_ALLOCATION_HINT_PREFERRED_METADATA, "PREFERRED_METADATA"},
+	{BTRFS_DEV_ALLOCATION_HINT_METADATA_ONLY, "METADATA_ONLY"},
+	{BTRFS_DEV_ALLOCATION_HINT_PREFERRED_DATA, "PREFERRED_DATA"},
+	{BTRFS_DEV_ALLOCATION_HINT_DATA_ONLY, "DATA_ONLY"},
+	{0, NULL}
+};
+
+static int prop_allocation_hint(enum prop_object_type type,
+				const char *object,
+				const char *name,
+				const char *value,
+				bool force)
+{
+	int ret, devid, fd, fd2;
+	char path[PATH_MAX];
+	DIR *dir;
+	u8 fsid[BTRFS_UUID_SIZE];
+	char fsid_str[BTRFS_UUID_UNPARSED_SIZE];
+	char sysfs_file[PATH_MAX];
+	char filename[PATH_MAX];
+	int i;
+	u64 v, devtype;
+	char buf[1024];
+
+	ret = btrfs_find_devid_and_mnt(object, &devid, path, sizeof(path));
+	if (ret)
+		return -5;
+
+	fd = btrfs_open_dir(path, &dir, 1);
+	if (fd < 0)
+		return fd;
+
+	ret = get_fsid_fd(fd, fsid);
+	if (ret < 0)
+		goto out;
+
+	uuid_unparse(fsid, fsid_str);
+	sprintf(filename, "devinfo/%d/allocation_hint", devid);
+
+	/* build /sys/fs/btrfs/<UUID>/devinfo/<DEVID>/type */
+	ret = path_cat3_out(sysfs_file, "/sys/fs/btrfs", fsid_str, filename);
+	if (ret < 0)
+		goto out;
+
+	fd2 = open(sysfs_file, O_RDONLY);
+	if (fd2 < 0) {
+		error("'allocation_hint' property not available or accessible.");
+		ret = -errno;
+		goto out;
+	}
+
+	ret = read(fd2, buf, sizeof(buf) - 1);
+	close(fd2);
+	if (ret < 0) {
+		error("Unable to read the 'allocation_hint' property.");
+		ret = -errno;
+		goto out;
+	}
+
+	buf[sizeof(buf) - 1] = 0;
+	devtype = strtoull(buf, NULL, 0);
+
+	if (!value) {
+		/* READ */
+		for (i = 0 ; allocation_hint_description[i].descr ; i++)
+			if (devtype == allocation_hint_description[i].value)
+				break;
+		if (allocation_hint_description[i].descr)
+			printf("devid=%d, path=%s: allocation_hint=%s\n",
+				devid, object,
+				allocation_hint_description[i].descr);
+		else
+			printf("devid=%d, path=%s: allocation_hint=unknown:%llu\n",
+				devid, object,
+				devtype);
+		ret = 0;
+	} else {
+		/* WRITE */
+		for (i = 0 ; allocation_hint_description[i].descr ; i++)
+			if (!strcmp(value, allocation_hint_description[i].descr))
+				break;
+
+		if (allocation_hint_description[i].descr) {
+			v = allocation_hint_description[i].value;
+		} else if (sscanf(value, "%llu", &v) != 1) {
+			error("Invalid value '%s'\n", value);
+			ret = -3;
+			goto out;
+		} 
+		if (v & ~BTRFS_DEV_ALLOCATION_HINT_MASK) {
+			error("Invalid value '%s'\n", value);
+			ret = -3;
+			goto out;
+		}
+
+		devtype &= ~BTRFS_DEV_ALLOCATION_HINT_MASK;
+		devtype |= (v & BTRFS_DEV_ALLOCATION_HINT_MASK);
+
+		fd2 = open(sysfs_file, O_RDWR);
+		if (fd2 < 0) {
+			error("'allocation_hint' property not available or accessible for updating.");
+			ret = -errno;
+			goto out;
+		}
+
+		sprintf(buf, "%llu", devtype);
+
+		ret = write(fd2, buf, strlen(buf));
+		close(fd2);
+		if (ret < 0) {
+			error("Unable to update 'allocation_hint' property.");
+			ret = -errno;
+			goto out;
+		}
+
+	}
+
+	ret = 0;
+out:
+	close_file_or_dir(fd, dir);
+	return ret;
+}
+
 const struct prop_handler prop_handlers[] = {
 	{
 		.name ="ro",
@@ -254,6 +452,12 @@ const struct prop_handler prop_handlers[] = {
 		.types = prop_object_inode,
 		.handler = prop_compression
 	},
+	{
+		.name = "allocation_hint",
+		.desc = "hint to store the data/metadata chunks",
+		.types = prop_object_dev,
+		.handler = prop_allocation_hint
+	},
 	{NULL, NULL, 0, 0, NULL}
 };
 
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 966490d3..adc869fe 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -213,6 +213,19 @@ struct btrfs_mapping_tree {
 	struct cache_tree cache_tree;
 };
 
+/* btrfs chunk allocation hints */
+#define BTRFS_DEV_ALLOCATION_HINT_BIT_COUNT    2
+#define BTRFS_DEV_ALLOCATION_HINT_MASK ((1ULL << \
+	       BTRFS_DEV_ALLOCATION_HINT_BIT_COUNT) - 1)
+/* preferred metadata chunk, but data chunk allowed */
+#define BTRFS_DEV_ALLOCATION_HINT_PREFERRED_METADATA        (1ULL)
+/* only metadata chunk are allowed */
+#define BTRFS_DEV_ALLOCATION_HINT_METADATA_ONLY     (2ULL)
+/* only data chunk allowed */
+#define BTRFS_DEV_ALLOCATION_HINT_DATA_ONLY         (3ULL)
+/* preferred data chunk, but metadata chunk allowed */
+#define BTRFS_DEV_ALLOCATION_HINT_PREFERRED_DATA    (0ULL)
+
 #define BTRFS_UUID_SIZE 16
 struct btrfs_dev_item {
 	/* the internal btrfs device id */
-- 
2.34.1


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

* [PATCH 2/2] Update man page for allocator_hint property.
  2021-12-17 18:47 [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
  2021-12-17 18:47 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
@ 2021-12-17 18:47 ` Goffredo Baroncelli
  2021-12-17 18:53 ` Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property] Goffredo Baroncelli
  2 siblings, 0 replies; 8+ messages in thread
From: Goffredo Baroncelli @ 2021-12-17 18:47 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
	Goffredo Baroncelli

From: Goffredo Baroncelli <kreijack@inwind.it>

Update the man page of the btrfs property subcommand to show the use
of the device property "allocation_hint".

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 Documentation/btrfs-property.asciidoc | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/Documentation/btrfs-property.asciidoc b/Documentation/btrfs-property.asciidoc
index b32d000e..d9e9c4b9 100644
--- a/Documentation/btrfs-property.asciidoc
+++ b/Documentation/btrfs-property.asciidoc
@@ -49,6 +49,23 @@ device as object. For a mounted filesystem, specify a mount point.
 compression::::
 compression algorithm set for an inode, possible values: 'lzo', 'zlib', 'zstd'.
 To disable compression use "" (empty string), 'no' or 'none'.
+allocation_hint::::
+a device property that instructs how and when the allocator should use a
+block device.
+Possible values are:
+- 'PREFERRED_METADATA': the device has an higher priority when a new metadata
+chunk is allocated. Data chunk is allowed only if there is no other possibility.
+- 'METADATA_ONLY': the device is used only for metadata chunk.
+Data chunk is never allowed.
+- 'PREFERRED_DATA' (default): the device has an higher priority when a new data
+chunk is allocated. Metadata chunk is allowed only if there is no other
+possibility.
+- 'DATA_ONLY': the device is used only for data chunk.
+Metadata chunk is never allowed.
+ ::::
+The default is 'PREFERRED_DATA'; if all the disks have this setting the
+allocator uses all of them with the same priority.
+
 
 *list* [-t <type>] <object>::
 Lists available properties with their descriptions for the given object.
-- 
2.34.1


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

* Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property]
  2021-12-17 18:47 [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
  2021-12-17 18:47 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
  2021-12-17 18:47 ` [PATCH 2/2] Update man page for allocator_hint property Goffredo Baroncelli
@ 2021-12-17 18:53 ` Goffredo Baroncelli
  2021-12-21  5:36   ` Paul Jones
  2 siblings, 1 reply; 8+ messages in thread
From: Goffredo Baroncelli @ 2021-12-17 18:53 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq

On 12/17/21 19:47, Goffredo Baroncelli wrote:
> From: Goffredo Baroncelli <kreijack@inwind.it>
> 
> This patches set is the userspace portion of the serie
> "[PATCH V9] btrfs: allocation_hint mode".
> 
> Look this patches set for further information.
> 
> G.Baroncelli
> 
> Goffredo Baroncelli (2):
>    btrfs-progs: new "allocation_hint" property.
>    Update man page for allocator_hint property.
> 
>   Documentation/btrfs-property.asciidoc |  17 +++
>   cmds/property.c                       | 204 ++++++++++++++++++++++++++
>   kernel-shared/ctree.h                 |  13 ++
>   3 files changed, 234 insertions(+)
> 


Below the script that I used to stress this patch. As is is not integrable in xfstest, but for now is better than nothing :-)

-----------
#!/bin/bash

#size of disk, smaller -> faster
MAXSIZE=$((1*1024*1024*1024))
MNT=mnt
BTRFS=./btrfs-hint
UUID=292afefb-6e8c-4fb3-9d12-8c4ecb1f237c

cleanup_all() {
	umount $MNT
	losetup -D
}

raise() {
	echo 1>&2 "$@"
	exit 100
}

xmount() {
	#mount -o allocation_hint=1 "$1" "$2"
	mount  "$1" "$2"
}

create_loops() {
	[ -n "$1" ] || {
		cleanup_all
		raise "Create_loops, missing an argument"
	}
	ret=""
	for i in $(seq "$1"); do
		disk=disk-$i.img
		rm -rf $disk
		truncate -s ${MAXSIZE} $disk
		losetup /dev/loop$i $disk
		ret="$ret /dev/loop$i"
	done

	echo "$ret"
}


fill_1_file() {
	fn=$MNT/giant-file-$1
	if [ -n "$2" ]; then
		size=count=$(($2 / 16 / 1024 / 1024 ))
	else
		size=
	fi
	dd if=/dev/zero of=$fn bs=16M oflag=direct $size
	ls -l $fn | awk '{ print $5 }'
}

dump_bg_data() {
	$BTRFS fi us -b $MNT | awk '
		/^$/    { flag=0 }
		        { if(flag) print $0 }
		/^Data/ { flag=1 }
	'
}

dump_bg_metadata() {
	$BTRFS fi us -b $MNT | awk '
		/^$/        { flag=0 }
		            { if(flag) print $0 }
		/^Metadata/ { flag=1 }
	'
}

test_default_raid1() {
	loops=$(create_loops 4)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	loop2=$(echo $loops | awk '{ print $3 }')
	loop3=$(echo $loops | awk '{ print $4 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
	xmount $loop0 $MNT
	
	size=$(fill_1_file x $(($MAXSIZE / 2)) )

	res=$(dump_bg_data)
	echo $res | egrep $loop0 || raise "Data BG should contains $loop0"
	echo $res | egrep $loop1 || raise "Data BG should contains $loop1"
	echo $res | egrep $loop2 || raise "Data BG should contains $loop2"
	echo $res | egrep $loop3 || raise "Data BG should contains $loop3"

	size1=$(fill_1_file y )

	size=$(($size + $size1))

	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] || raise "File too small: check mnt/"
	[ $size -lt $(($MAXSIZE * 2 * 3 / 2 )) ] || raise "File too big: check mnt/"

	cleanup_all
}

test_default_single() {
	loops=$(create_loops 2)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -dsingle -msingle $loops
	xmount $loop0 $MNT
	
	size=$(fill_1_file x $(($MAXSIZE / 2)) )

	res=$(dump_bg_data)
	echo $res | egrep $loop0 || raise "Data BG should contains $loop0"
	echo $res | egrep $loop1 || raise "Data BG should contains $loop1"

	size1=$(fill_1_file y )

	size=$(($size + $size1))

	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] || raise "File too small: check mnt/"
	[ $size -lt $(($MAXSIZE * 2 * 3 / 2 )) ] || raise "File too big: check mnt/"

	cleanup_all
}

test_single_preferred_data() {
	loops=$(create_loops 2)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -dsingle -msingle $loops
	xmount $loop0 $MNT

	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
	$BTRFS prop set $loop1 allocation_hint PREFERRED_DATA
	
	$BTRFS balance start --full-balance $MNT

	size=$(fill_1_file x $(($MAXSIZE / 2)) )

	res=$(dump_bg_data)
	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not contains $loop0"
	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should contains $loop3"

	cleanup_all
}

test_single_preferred_metadata() {
	loops=$(create_loops 2)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -dsingle -msingle $loops
	xmount $loop0 $MNT

	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
	$BTRFS prop set $loop1 allocation_hint PREFERRED_DATA
	
	$BTRFS balance start --full-balance $MNT

	fnsize=2048
	for i in $(seq $(( $MAXSIZE / $fnsize * 700 / 1000))); do
		dd if=/dev/zero of=$MNT/fn-$i bs=$fnsize count=1
	done

	#BTRFS fi us $MNT

	res=$(dump_bg_metadata)
	echo $res | egrep $loop0 &>/dev/null || raise "Metadata BG should contains $loop0"
	echo $res | egrep $loop1 &>/dev/null && raise "Metadata BG should contains $loop3"

	cleanup_all
}



test_raid1_preferred_data() {
	loops=$(create_loops 4)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	loop2=$(echo $loops | awk '{ print $3 }')
	loop3=$(echo $loops | awk '{ print $4 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
	xmount $loop0 $MNT

	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
	$BTRFS prop set $loop1 allocation_hint PREFERRED_METADATA
	$BTRFS prop set $loop2 allocation_hint PREFERRED_DATA
	$BTRFS prop set $loop3 allocation_hint PREFERRED_DATA
	
	$BTRFS balance start --full-balance $MNT

	size=$(fill_1_file x $(($MAXSIZE / 2)) )

	res=$(dump_bg_data)
	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not contains $loop0"
	echo $res | egrep $loop1 &>/dev/null && raise "Data BG should not contains $loop1"
	echo $res | egrep $loop2 &>/dev/null || raise "Data BG should contains $loop2"
	echo $res | egrep $loop3 &>/dev/null || raise "Data BG should contains $loop3"

	cleanup_all
}

test_raid1_preferred_metadata() {
	loops=$(create_loops 4)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	loop2=$(echo $loops | awk '{ print $3 }')
	loop3=$(echo $loops | awk '{ print $4 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
	xmount $loop0 $MNT

	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
	$BTRFS prop set $loop1 allocation_hint PREFERRED_METADATA
	$BTRFS prop set $loop2 allocation_hint PREFERRED_DATA
	$BTRFS prop set $loop3 allocation_hint PREFERRED_DATA
	
	$BTRFS balance start --full-balance $MNT

	fnsize=2048
	for i in $(seq $(( $MAXSIZE / $fnsize * 700 / 1000))); do
		dd if=/dev/zero of=$MNT/fn-$i bs=$fnsize count=1
	done

	#BTRFS fi us $MNT

	res=$(dump_bg_metadata)
	echo $res | egrep $loop0 &>/dev/null || raise "Metadata BG should contains $loop0"
	echo $res | egrep $loop1 &>/dev/null || raise "Metadata BG should contains $loop1"
	echo $res | egrep $loop2 &>/dev/null && raise "Metadata BG should contains $loop2"
	echo $res | egrep $loop3 &>/dev/null && raise "Metadata BG should contains $loop3"

	cleanup_all
}

test_raid1_data_only() {
	loops=$(create_loops 4)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	loop2=$(echo $loops | awk '{ print $3 }')
	loop3=$(echo $loops | awk '{ print $4 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
	xmount $loop0 $MNT

	$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
	$BTRFS prop set $loop1 allocation_hint METADATA_ONLY
	$BTRFS prop set $loop2 allocation_hint DATA_ONLY
	$BTRFS prop set $loop3 allocation_hint DATA_ONLY
	
	$BTRFS balance start --full-balance $MNT

	size=$(fill_1_file x  )

	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] && raise "File too big: check mnt/"
	[ $size -lt $(($MAXSIZE * 2 / 3 )) ] && raise "File too small: check mnt/"

	res=$(dump_bg_data)
	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not contains $loop0"
	echo $res | egrep $loop1 &>/dev/null && raise "Data BG should not contains $loop1"
	echo $res | egrep $loop2 &>/dev/null || raise "Data BG should contains $loop2"
	echo $res | egrep $loop3 &>/dev/null || raise "Data BG should contains $loop3"

	cleanup_all
}

test_single_data_only() {
	loops=$(create_loops 2)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -dsingle -msingle $loops
	xmount $loop0 $MNT

	$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
	$BTRFS prop set $loop1 allocation_hint DATA_ONLY
	
	$BTRFS balance start --full-balance $MNT

	size=$(fill_1_file x  )

	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] && raise "File too big: check mnt/"
	[ $size -lt $(($MAXSIZE * 2 / 3 )) ] && raise "File too small: check mnt/"

	res=$(dump_bg_data)
	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not contains $loop0"
	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should contains $loop3"

	cleanup_all
}


test_single_data_bouncing() {
	loops=$(create_loops 2)
	loop0=$(echo $loops | awk '{ print $1 }')
	loop1=$(echo $loops | awk '{ print $2 }')
	$BTRFS dev scan -u
	mkfs.btrfs -U $UUID -dsingle -msingle $loops
	xmount $loop0 $MNT

	$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
	$BTRFS prop set $loop1 allocation_hint DATA_ONLY
	
	$BTRFS balance start --full-balance $MNT

	size=$(fill_1_file x  $(($MAXSIZE * 2 / 4 )))

	[ $size -gt $(($MAXSIZE * 2 / 3 )) ] && raise "File too big: check mnt/"
	[ $size -lt $(($MAXSIZE * 1 / 3 )) ] && raise "File too small: check mnt/"

	res=$(dump_bg_data)

	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not contains $loop0"
	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should contains $loop1"

	$BTRFS balance start --full-balance $MNT

	res=$(dump_bg_data)

	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not contains $loop0"
	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should contains $loop1"


	$BTRFS prop set $loop1 allocation_hint METADATA_ONLY
	$BTRFS prop set $loop0 allocation_hint DATA_ONLY

	$BTRFS balance start --full-balance $MNT

	res=$(dump_bg_data)

	echo $res | egrep $loop1 &>/dev/null && raise "Data BG should not contains $loop1"
	echo $res | egrep $loop0 &>/dev/null || raise "Data BG should contains $loop0"
	cleanup_all
}








if [ "$1" = "cleanup" ]; then
	cleanup_all

	exit
elif [ "$1" = "makeraid1" ]; then
	loops=$(create_loops 4)
	loop0=$(echo $loops | awk '{ print $1 }')
	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
	xmount $loop0 $MNT

	exit
fi


cleanup_all &>/dev/null
cleanup_all &>/dev/null

SETV=""
SETX=""

while true; do
	if [ "$1" = "-x" ]; then
		SETX="set -x"
		shift
	elif [ "$1" = "-v" ]; then
		SETV="-v"
		shift
	elif [ "$1" = "--list" ]; then
		declare -F | awk '{ print $3 }' | egrep ^test_ | sort
		exit
	else
		break
	fi
done

ARG="$1"

$SETX


[ -z "$ARG" ] && ARG="."
declare -F | awk '{ print $3 }' | egrep ^test_ | sort |
	egrep $SETV "$ARG" | while read func; do

	echo -n "TEST '$func' "
	(
		$SETX
		$func >.out.log 2>.err.log
	)|| raise "Error !!!; read .out.log, .err.log"
	echo "OK"
done

-----------



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli <kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* RE: Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property]
  2021-12-17 18:53 ` Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property] Goffredo Baroncelli
@ 2021-12-21  5:36   ` Paul Jones
  2021-12-21 20:58     ` Goffredo Baroncelli
  0 siblings, 1 reply; 8+ messages in thread
From: Paul Jones @ 2021-12-21  5:36 UTC (permalink / raw)
  To: kreijack, linux-btrfs
  Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq



> -----Original Message-----
> From: Goffredo Baroncelli <kreijack@libero.it>
> Sent: Saturday, 18 December 2021 5:53 AM
> To: linux-btrfs@vger.kernel.org
> Cc: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>; Josef Bacik
> <josef@toxicpanda.com>; David Sterba <dsterba@suse.cz>; Sinnamohideen
> Shafeeq <shafeeqs@panasas.com>
> Subject: Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs:
> allocation_hint disk property]
> 
> On 12/17/21 19:47, Goffredo Baroncelli wrote:
> > From: Goffredo Baroncelli <kreijack@inwind.it>
> >
> > This patches set is the userspace portion of the serie "[PATCH V9]
> > btrfs: allocation_hint mode".
> >
> > Look this patches set for further information.
> >
> > G.Baroncelli
> >
> > Goffredo Baroncelli (2):
> >    btrfs-progs: new "allocation_hint" property.
> >    Update man page for allocator_hint property.
> >
> >   Documentation/btrfs-property.asciidoc |  17 +++
> >   cmds/property.c                       | 204 ++++++++++++++++++++++++++
> >   kernel-shared/ctree.h                 |  13 ++
> >   3 files changed, 234 insertions(+)
> >
> 
> 
> Below the script that I used to stress this patch. As is is not integrable in
> xfstest, but for now is better than nothing :-)


FYI something has broken in 5.15 - Only the first device in a raid set gets allocation_hint set

server /media/storage/peejay/linux/btrfs-progs # cat .err.log
dd: error writing 'mnt/giant-file-x': No space left on device
110+0 records in
109+0 records out
1828716544 bytes (1.8 GB, 1.7 GiB) copied, 4.4846 s, 408 MB/s
File too big: check mnt/
server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop1
label=
devid=1, path=/dev/loop1: allocation_hint=METADATA_ONLY
server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop2
label=
server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop3
label=
server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop4
label=



> 
> -----------
> #!/bin/bash
> 
> #size of disk, smaller -> faster
> MAXSIZE=$((1*1024*1024*1024))
> MNT=mnt
> BTRFS=./btrfs-hint
> UUID=292afefb-6e8c-4fb3-9d12-8c4ecb1f237c
> 
> cleanup_all() {
> 	umount $MNT
> 	losetup -D
> }
> 
> raise() {
> 	echo 1>&2 "$@"
> 	exit 100
> }
> 
> xmount() {
> 	#mount -o allocation_hint=1 "$1" "$2"
> 	mount  "$1" "$2"
> }
> 
> create_loops() {
> 	[ -n "$1" ] || {
> 		cleanup_all
> 		raise "Create_loops, missing an argument"
> 	}
> 	ret=""
> 	for i in $(seq "$1"); do
> 		disk=disk-$i.img
> 		rm -rf $disk
> 		truncate -s ${MAXSIZE} $disk
> 		losetup /dev/loop$i $disk
> 		ret="$ret /dev/loop$i"
> 	done
> 
> 	echo "$ret"
> }
> 
> 
> fill_1_file() {
> 	fn=$MNT/giant-file-$1
> 	if [ -n "$2" ]; then
> 		size=count=$(($2 / 16 / 1024 / 1024 ))
> 	else
> 		size=
> 	fi
> 	dd if=/dev/zero of=$fn bs=16M oflag=direct $size
> 	ls -l $fn | awk '{ print $5 }'
> }
> 
> dump_bg_data() {
> 	$BTRFS fi us -b $MNT | awk '
> 		/^$/    { flag=0 }
> 		        { if(flag) print $0 }
> 		/^Data/ { flag=1 }
> 	'
> }
> 
> dump_bg_metadata() {
> 	$BTRFS fi us -b $MNT | awk '
> 		/^$/        { flag=0 }
> 		            { if(flag) print $0 }
> 		/^Metadata/ { flag=1 }
> 	'
> }
> 
> test_default_raid1() {
> 	loops=$(create_loops 4)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	loop2=$(echo $loops | awk '{ print $3 }')
> 	loop3=$(echo $loops | awk '{ print $4 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
> 	xmount $loop0 $MNT
> 
> 	size=$(fill_1_file x $(($MAXSIZE / 2)) )
> 
> 	res=$(dump_bg_data)
> 	echo $res | egrep $loop0 || raise "Data BG should contains $loop0"
> 	echo $res | egrep $loop1 || raise "Data BG should contains $loop1"
> 	echo $res | egrep $loop2 || raise "Data BG should contains $loop2"
> 	echo $res | egrep $loop3 || raise "Data BG should contains $loop3"
> 
> 	size1=$(fill_1_file y )
> 
> 	size=$(($size + $size1))
> 
> 	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] || raise "File too small: check
> mnt/"
> 	[ $size -lt $(($MAXSIZE * 2 * 3 / 2 )) ] || raise "File too big: check
> mnt/"
> 
> 	cleanup_all
> }
> 
> test_default_single() {
> 	loops=$(create_loops 2)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -dsingle -msingle $loops
> 	xmount $loop0 $MNT
> 
> 	size=$(fill_1_file x $(($MAXSIZE / 2)) )
> 
> 	res=$(dump_bg_data)
> 	echo $res | egrep $loop0 || raise "Data BG should contains $loop0"
> 	echo $res | egrep $loop1 || raise "Data BG should contains $loop1"
> 
> 	size1=$(fill_1_file y )
> 
> 	size=$(($size + $size1))
> 
> 	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] || raise "File too small: check
> mnt/"
> 	[ $size -lt $(($MAXSIZE * 2 * 3 / 2 )) ] || raise "File too big: check
> mnt/"
> 
> 	cleanup_all
> }
> 
> test_single_preferred_data() {
> 	loops=$(create_loops 2)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -dsingle -msingle $loops
> 	xmount $loop0 $MNT
> 
> 	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
> 	$BTRFS prop set $loop1 allocation_hint PREFERRED_DATA
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	size=$(fill_1_file x $(($MAXSIZE / 2)) )
> 
> 	res=$(dump_bg_data)
> 	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should
> contains $loop3"
> 
> 	cleanup_all
> }
> 
> test_single_preferred_metadata() {
> 	loops=$(create_loops 2)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -dsingle -msingle $loops
> 	xmount $loop0 $MNT
> 
> 	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
> 	$BTRFS prop set $loop1 allocation_hint PREFERRED_DATA
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	fnsize=2048
> 	for i in $(seq $(( $MAXSIZE / $fnsize * 700 / 1000))); do
> 		dd if=/dev/zero of=$MNT/fn-$i bs=$fnsize count=1
> 	done
> 
> 	#BTRFS fi us $MNT
> 
> 	res=$(dump_bg_metadata)
> 	echo $res | egrep $loop0 &>/dev/null || raise "Metadata BG should
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null && raise "Metadata BG should
> contains $loop3"
> 
> 	cleanup_all
> }
> 
> 
> 
> test_raid1_preferred_data() {
> 	loops=$(create_loops 4)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	loop2=$(echo $loops | awk '{ print $3 }')
> 	loop3=$(echo $loops | awk '{ print $4 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
> 	xmount $loop0 $MNT
> 
> 	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
> 	$BTRFS prop set $loop1 allocation_hint PREFERRED_METADATA
> 	$BTRFS prop set $loop2 allocation_hint PREFERRED_DATA
> 	$BTRFS prop set $loop3 allocation_hint PREFERRED_DATA
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	size=$(fill_1_file x $(($MAXSIZE / 2)) )
> 
> 	res=$(dump_bg_data)
> 	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null && raise "Data BG should not
> contains $loop1"
> 	echo $res | egrep $loop2 &>/dev/null || raise "Data BG should
> contains $loop2"
> 	echo $res | egrep $loop3 &>/dev/null || raise "Data BG should
> contains $loop3"
> 
> 	cleanup_all
> }
> 
> test_raid1_preferred_metadata() {
> 	loops=$(create_loops 4)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	loop2=$(echo $loops | awk '{ print $3 }')
> 	loop3=$(echo $loops | awk '{ print $4 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
> 	xmount $loop0 $MNT
> 
> 	$BTRFS prop set $loop0 allocation_hint PREFERRED_METADATA
> 	$BTRFS prop set $loop1 allocation_hint PREFERRED_METADATA
> 	$BTRFS prop set $loop2 allocation_hint PREFERRED_DATA
> 	$BTRFS prop set $loop3 allocation_hint PREFERRED_DATA
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	fnsize=2048
> 	for i in $(seq $(( $MAXSIZE / $fnsize * 700 / 1000))); do
> 		dd if=/dev/zero of=$MNT/fn-$i bs=$fnsize count=1
> 	done
> 
> 	#BTRFS fi us $MNT
> 
> 	res=$(dump_bg_metadata)
> 	echo $res | egrep $loop0 &>/dev/null || raise "Metadata BG should
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null || raise "Metadata BG should
> contains $loop1"
> 	echo $res | egrep $loop2 &>/dev/null && raise "Metadata BG should
> contains $loop2"
> 	echo $res | egrep $loop3 &>/dev/null && raise "Metadata BG should
> contains $loop3"
> 
> 	cleanup_all
> }
> 
> test_raid1_data_only() {
> 	loops=$(create_loops 4)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	loop2=$(echo $loops | awk '{ print $3 }')
> 	loop3=$(echo $loops | awk '{ print $4 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
> 	xmount $loop0 $MNT
> 
> 	$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
> 	$BTRFS prop set $loop1 allocation_hint METADATA_ONLY
> 	$BTRFS prop set $loop2 allocation_hint DATA_ONLY
> 	$BTRFS prop set $loop3 allocation_hint DATA_ONLY
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	size=$(fill_1_file x  )
> 
> 	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] && raise "File too big: check
> mnt/"
> 	[ $size -lt $(($MAXSIZE * 2 / 3 )) ] && raise "File too small: check mnt/"
> 
> 	res=$(dump_bg_data)
> 	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null && raise "Data BG should not
> contains $loop1"
> 	echo $res | egrep $loop2 &>/dev/null || raise "Data BG should
> contains $loop2"
> 	echo $res | egrep $loop3 &>/dev/null || raise "Data BG should
> contains $loop3"
> 
> 	cleanup_all
> }
> 
> test_single_data_only() {
> 	loops=$(create_loops 2)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -dsingle -msingle $loops
> 	xmount $loop0 $MNT
> 
> 	$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
> 	$BTRFS prop set $loop1 allocation_hint DATA_ONLY
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	size=$(fill_1_file x  )
> 
> 	[ $size -gt $(($MAXSIZE * 2 * 2 / 3 )) ] && raise "File too big: check
> mnt/"
> 	[ $size -lt $(($MAXSIZE * 2 / 3 )) ] && raise "File too small: check mnt/"
> 
> 	res=$(dump_bg_data)
> 	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should
> contains $loop3"
> 
> 	cleanup_all
> }
> 
> 
> test_single_data_bouncing() {
> 	loops=$(create_loops 2)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	loop1=$(echo $loops | awk '{ print $2 }')
> 	$BTRFS dev scan -u
> 	mkfs.btrfs -U $UUID -dsingle -msingle $loops
> 	xmount $loop0 $MNT
> 
> 	$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
> 	$BTRFS prop set $loop1 allocation_hint DATA_ONLY
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	size=$(fill_1_file x  $(($MAXSIZE * 2 / 4 )))
> 
> 	[ $size -gt $(($MAXSIZE * 2 / 3 )) ] && raise "File too big: check mnt/"
> 	[ $size -lt $(($MAXSIZE * 1 / 3 )) ] && raise "File too small: check mnt/"
> 
> 	res=$(dump_bg_data)
> 
> 	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should
> contains $loop1"
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	res=$(dump_bg_data)
> 
> 	echo $res | egrep $loop0 &>/dev/null && raise "Data BG should not
> contains $loop0"
> 	echo $res | egrep $loop1 &>/dev/null || raise "Data BG should
> contains $loop1"
> 
> 
> 	$BTRFS prop set $loop1 allocation_hint METADATA_ONLY
> 	$BTRFS prop set $loop0 allocation_hint DATA_ONLY
> 
> 	$BTRFS balance start --full-balance $MNT
> 
> 	res=$(dump_bg_data)
> 
> 	echo $res | egrep $loop1 &>/dev/null && raise "Data BG should not
> contains $loop1"
> 	echo $res | egrep $loop0 &>/dev/null || raise "Data BG should
> contains $loop0"
> 	cleanup_all
> }
> 
> 
> 
> 
> 
> 
> 
> 
> if [ "$1" = "cleanup" ]; then
> 	cleanup_all
> 
> 	exit
> elif [ "$1" = "makeraid1" ]; then
> 	loops=$(create_loops 4)
> 	loop0=$(echo $loops | awk '{ print $1 }')
> 	mkfs.btrfs -U $UUID -draid1 -mraid1 $loops
> 	xmount $loop0 $MNT
> 
> 	exit
> fi
> 
> 
> cleanup_all &>/dev/null
> cleanup_all &>/dev/null
> 
> SETV=""
> SETX=""
> 
> while true; do
> 	if [ "$1" = "-x" ]; then
> 		SETX="set -x"
> 		shift
> 	elif [ "$1" = "-v" ]; then
> 		SETV="-v"
> 		shift
> 	elif [ "$1" = "--list" ]; then
> 		declare -F | awk '{ print $3 }' | egrep ^test_ | sort
> 		exit
> 	else
> 		break
> 	fi
> done
> 
> ARG="$1"
> 
> $SETX
> 
> 
> [ -z "$ARG" ] && ARG="."
> declare -F | awk '{ print $3 }' | egrep ^test_ | sort |
> 	egrep $SETV "$ARG" | while read func; do
> 
> 	echo -n "TEST '$func' "
> 	(
> 		$SETX
> 		$func >.out.log 2>.err.log
> 	)|| raise "Error !!!; read .out.log, .err.log"
> 	echo "OK"
> done
> 
> -----------
> 
> 
> 
> --
> gpg @keyserver.linux.it: Goffredo Baroncelli <kreijackATinwind.it> Key
> fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property]
  2021-12-21  5:36   ` Paul Jones
@ 2021-12-21 20:58     ` Goffredo Baroncelli
  0 siblings, 0 replies; 8+ messages in thread
From: Goffredo Baroncelli @ 2021-12-21 20:58 UTC (permalink / raw)
  To: Paul Jones
  Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
	linux-btrfs

On 12/21/21 06:36, Paul Jones wrote:

> 
> FYI something has broken in 5.15 - Only the first device in a raid set gets allocation_hint set
> 
> server /media/storage/peejay/linux/btrfs-progs # cat .err.log
> dd: error writing 'mnt/giant-file-x': No space left on device
> 110+0 records in
> 109+0 records out
> 1828716544 bytes (1.8 GB, 1.7 GiB) copied, 4.4846 s, 408 MB/s
> File too big: check mnt/
> server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop1
> label=
> devid=1, path=/dev/loop1: allocation_hint=METADATA_ONLY
> server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop2
> label=
> server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop3
> label=
> server /media/storage/peejay/linux/btrfs-progs # ./btrfs-hint prop get /dev/loop4
> label=
> 

Yes, I can reproduce it. However the strange if I do

# sudo ./btrfs prop get /dev/loop1 allocation_hint
devid=2, path=/dev/loop1: allocation_hint=DATA_PREFERRED

it works; instead if I do (no property name)

# sudo ./btrfs prop get /dev/loop1
label=

it doesn't work.


My suspect is that the guilty is get_label() and how the "global" internal state of btrfs is not re-entrant.

Let me to explain what (I think) happens: if you don't pass a property name to "btrfs get prop", btrfs-progs iterates over all the "get" properties handlers.
One of these handlers is the manager of the "label" property. This handler check the kind of object passed. If the object is a device (like this case), it assume that the filesystem is not mounted and call get_label_unmounted (otherwise it calls the get_label_mounted, which in turn ask the label using an ioctl).
get_label_unmounted() instead calls open_ctree() (anyway I suspect that this is not a good thing on an mounted filesystem).

My *suspect* is that open_ctree()/close_ctree() (called by get_label) and btrfs_scan_devices() (called by the allocation_hint handler) interact badly.
In fact if I comment the code of get_label_unmounted(), the bug goes away.

In conclusion, yes there is a BUG. The bug is raise when "btrfs get prop <obj>" is called without a specific property. It seems not related to the code of the allocation_hint property, but how the internal state of btrfs is handled in general. But a more deeper analysis is needed.

BR

-- 
gpg @keyserver.linux.it: Goffredo Baroncelli <kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

-- 
gpg @keyserver.linux.it: Goffredo Baroncelli <kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH 1/2] btrfs-progs: new "allocation_hint" property.
  2021-12-17 18:47 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
@ 2022-01-05  2:29   ` Boris Burkov
  2022-01-05  9:19     ` Goffredo Baroncelli
  0 siblings, 1 reply; 8+ messages in thread
From: Boris Burkov @ 2022-01-05  2:29 UTC (permalink / raw)
  To: Goffredo Baroncelli
  Cc: linux-btrfs, Zygo Blaxell, Josef Bacik, David Sterba,
	Sinnamohideen Shafeeq, Goffredo Baroncelli

On Fri, Dec 17, 2021 at 07:47:04PM +0100, Goffredo Baroncelli wrote:
> From: Goffredo Baroncelli <kreijack@inwind.it>
> 
> Handle the property allocation_hint of a btrfs device. Below
> an example of use:
> 
> $ # set a new value
> $ sudo btrfs property set /dev/vde allocation_hint DATA_ONLY

I applied this patchset to the master branch of
git://github.com/kdave/btrfs-progs.git
and this command failed with something like "not a btrfs object".

However, it worked fine as:
$ sudo btrfs property set -t device /dev/DEV allocation_hint DATA_ONLY

I can't think of a reason I would hit this error and you wouldn't, since
that check is relatively old, but figured I would mention it.

> 
> $ # get the current value
> $ sudo btrfs property get /dev/vde allocation_hint
> devid=4, path=/dev/vde: allocation_hint=DATA_ONLY
> 
> The following values are availables:
> - DATA_ONLY
> - PREFERRED_DATA (default)
> - PREFERRED_METADATA
> - METADATA_ONLY
> 
> Root privileges are required.
> 
> Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
> ---
>  cmds/property.c       | 204 ++++++++++++++++++++++++++++++++++++++++++
>  kernel-shared/ctree.h |  13 +++
>  2 files changed, 217 insertions(+)
> 
> diff --git a/cmds/property.c b/cmds/property.c
> index 59ef997c..e6a38ee1 100644
> --- a/cmds/property.c
> +++ b/cmds/property.c
> @@ -22,6 +22,7 @@
>  #include <sys/ioctl.h>
>  #include <sys/stat.h>
>  #include <sys/xattr.h>
> +#include <sys/sysmacros.h>
>  #include <uuid/uuid.h>
>  #include <btrfsutil.h>
>  #include "cmds/commands.h"
> @@ -30,6 +31,7 @@
>  #include "common/open-utils.h"
>  #include "common/utils.h"
>  #include "common/help.h"
> +#include "common/path-utils.h"
>  
>  #define XATTR_BTRFS_PREFIX     "btrfs."
>  #define XATTR_BTRFS_PREFIX_LEN (sizeof(XATTR_BTRFS_PREFIX) - 1)
> @@ -232,6 +234,202 @@ out:
>  	return ret;
>  }
>  
> +static int btrfs_find_devid_and_mnt(const char *devpath, int *devid,
> +				    char *path, int maxpath)
> +{
> +	int ret, i, fd;
> +	DIR *dir;
> +	struct stat stdevpath;
> +	struct btrfs_ioctl_fs_info_args fi_args;
> +	struct btrfs_ioctl_dev_info_args dev_info;
> +
> +	ret = get_btrfs_mount(devpath, path, maxpath);
> +	if (ret)
> +		return ret;
> +
> +	fd = btrfs_open_dir(path, &dir, 1);
> +	if (fd < 0)
> +		return fd;
> +
> +	ret = stat(devpath, &stdevpath);
> +	if (ret) {
> +		error("cannot stat '%s'", devpath);
> +		goto out;
> +	}
> +
> +	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
> +	if (ret < 0) {
> +		if (errno == EPERM)
> +			return -errno;
> +		error("cannot get filesystem info: %m");
> +		ret = -10;
> +		goto out;
> +	}
> +
> +	for (i = 0 ; i <= fi_args.max_id ; i++) {
> +		struct stat st;
> +
> +		memset(&dev_info, 0, sizeof(dev_info));
> +		ret = get_device_info(fd, i, &dev_info);
> +		if (ret == -ENODEV)
> +			continue;
> +		if (ret) {
> +			error("cannot get info about device devid=%d", i);
> +			goto out;
> +		}
> +
> +		if (!dev_info.path)
> +			/* missing devices */
> +			continue;
> +
> +		ret = stat((char *)dev_info.path, &st);
> +		if (ret) {
> +			error("cannot stat '%s'", devpath);
> +			goto out;
> +		}
> +
> +		if (major(st.st_rdev) == major(stdevpath.st_rdev) &&
> +		    minor(st.st_rdev) == minor(stdevpath.st_rdev)) {
> +			*devid = dev_info.devid;
> +			ret = 0;
> +			goto out;
> +		}
> +	}
> +
> +	ret = -12;
> +
> +out:
> +	close_file_or_dir(fd, dir);
> +	return ret;
> +}
> +
> +static struct ull_charp_pair_t {
> +	u64		value;
> +	const char	*descr;
> +} allocation_hint_description[] = {
> +	{BTRFS_DEV_ALLOCATION_HINT_PREFERRED_METADATA, "PREFERRED_METADATA"},
> +	{BTRFS_DEV_ALLOCATION_HINT_METADATA_ONLY, "METADATA_ONLY"},
> +	{BTRFS_DEV_ALLOCATION_HINT_PREFERRED_DATA, "PREFERRED_DATA"},
> +	{BTRFS_DEV_ALLOCATION_HINT_DATA_ONLY, "DATA_ONLY"},
> +	{0, NULL}
> +};
> +
> +static int prop_allocation_hint(enum prop_object_type type,
> +				const char *object,
> +				const char *name,
> +				const char *value,
> +				bool force)
> +{
> +	int ret, devid, fd, fd2;
> +	char path[PATH_MAX];
> +	DIR *dir;
> +	u8 fsid[BTRFS_UUID_SIZE];
> +	char fsid_str[BTRFS_UUID_UNPARSED_SIZE];
> +	char sysfs_file[PATH_MAX];
> +	char filename[PATH_MAX];
> +	int i;
> +	u64 v, devtype;
> +	char buf[1024];
> +
> +	ret = btrfs_find_devid_and_mnt(object, &devid, path, sizeof(path));
> +	if (ret)
> +		return -5;
> +
> +	fd = btrfs_open_dir(path, &dir, 1);
> +	if (fd < 0)
> +		return fd;
> +
> +	ret = get_fsid_fd(fd, fsid);
> +	if (ret < 0)
> +		goto out;
> +
> +	uuid_unparse(fsid, fsid_str);
> +	sprintf(filename, "devinfo/%d/allocation_hint", devid);
> +
> +	/* build /sys/fs/btrfs/<UUID>/devinfo/<DEVID>/type */
> +	ret = path_cat3_out(sysfs_file, "/sys/fs/btrfs", fsid_str, filename);
> +	if (ret < 0)
> +		goto out;
> +
> +	fd2 = open(sysfs_file, O_RDONLY);
> +	if (fd2 < 0) {
> +		error("'allocation_hint' property not available or accessible.");
> +		ret = -errno;
> +		goto out;
> +	}
> +
> +	ret = read(fd2, buf, sizeof(buf) - 1);
> +	close(fd2);
> +	if (ret < 0) {
> +		error("Unable to read the 'allocation_hint' property.");
> +		ret = -errno;
> +		goto out;
> +	}
> +
> +	buf[sizeof(buf) - 1] = 0;
> +	devtype = strtoull(buf, NULL, 0);
> +
> +	if (!value) {
> +		/* READ */
> +		for (i = 0 ; allocation_hint_description[i].descr ; i++)
> +			if (devtype == allocation_hint_description[i].value)
> +				break;
> +		if (allocation_hint_description[i].descr)
> +			printf("devid=%d, path=%s: allocation_hint=%s\n",
> +				devid, object,
> +				allocation_hint_description[i].descr);
> +		else
> +			printf("devid=%d, path=%s: allocation_hint=unknown:%llu\n",
> +				devid, object,
> +				devtype);
> +		ret = 0;
> +	} else {
> +		/* WRITE */
> +		for (i = 0 ; allocation_hint_description[i].descr ; i++)
> +			if (!strcmp(value, allocation_hint_description[i].descr))
> +				break;
> +
> +		if (allocation_hint_description[i].descr) {
> +			v = allocation_hint_description[i].value;
> +		} else if (sscanf(value, "%llu", &v) != 1) {
> +			error("Invalid value '%s'\n", value);
> +			ret = -3;
> +			goto out;
> +		} 
> +		if (v & ~BTRFS_DEV_ALLOCATION_HINT_MASK) {
> +			error("Invalid value '%s'\n", value);
> +			ret = -3;
> +			goto out;
> +		}
> +
> +		devtype &= ~BTRFS_DEV_ALLOCATION_HINT_MASK;
> +		devtype |= (v & BTRFS_DEV_ALLOCATION_HINT_MASK);
> +
> +		fd2 = open(sysfs_file, O_RDWR);
> +		if (fd2 < 0) {
> +			error("'allocation_hint' property not available or accessible for updating.");
> +			ret = -errno;
> +			goto out;
> +		}
> +
> +		sprintf(buf, "%llu", devtype);
> +
> +		ret = write(fd2, buf, strlen(buf));
> +		close(fd2);
> +		if (ret < 0) {
> +			error("Unable to update 'allocation_hint' property.");
> +			ret = -errno;
> +			goto out;
> +		}
> +
> +	}
> +
> +	ret = 0;
> +out:
> +	close_file_or_dir(fd, dir);
> +	return ret;
> +}
> +
>  const struct prop_handler prop_handlers[] = {
>  	{
>  		.name ="ro",
> @@ -254,6 +452,12 @@ const struct prop_handler prop_handlers[] = {
>  		.types = prop_object_inode,
>  		.handler = prop_compression
>  	},
> +	{
> +		.name = "allocation_hint",
> +		.desc = "hint to store the data/metadata chunks",
> +		.types = prop_object_dev,
> +		.handler = prop_allocation_hint
> +	},
>  	{NULL, NULL, 0, 0, NULL}
>  };
>  
> diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
> index 966490d3..adc869fe 100644
> --- a/kernel-shared/ctree.h
> +++ b/kernel-shared/ctree.h
> @@ -213,6 +213,19 @@ struct btrfs_mapping_tree {
>  	struct cache_tree cache_tree;
>  };
>  
> +/* btrfs chunk allocation hints */
> +#define BTRFS_DEV_ALLOCATION_HINT_BIT_COUNT    2
> +#define BTRFS_DEV_ALLOCATION_HINT_MASK ((1ULL << \
> +	       BTRFS_DEV_ALLOCATION_HINT_BIT_COUNT) - 1)
> +/* preferred metadata chunk, but data chunk allowed */
> +#define BTRFS_DEV_ALLOCATION_HINT_PREFERRED_METADATA        (1ULL)
> +/* only metadata chunk are allowed */
> +#define BTRFS_DEV_ALLOCATION_HINT_METADATA_ONLY     (2ULL)
> +/* only data chunk allowed */
> +#define BTRFS_DEV_ALLOCATION_HINT_DATA_ONLY         (3ULL)
> +/* preferred data chunk, but metadata chunk allowed */
> +#define BTRFS_DEV_ALLOCATION_HINT_PREFERRED_DATA    (0ULL)
> +
>  #define BTRFS_UUID_SIZE 16
>  struct btrfs_dev_item {
>  	/* the internal btrfs device id */
> -- 
> 2.34.1
> 

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

* Re: [PATCH 1/2] btrfs-progs: new "allocation_hint" property.
  2022-01-05  2:29   ` Boris Burkov
@ 2022-01-05  9:19     ` Goffredo Baroncelli
  0 siblings, 0 replies; 8+ messages in thread
From: Goffredo Baroncelli @ 2022-01-05  9:19 UTC (permalink / raw)
  To: Boris Burkov
  Cc: linux-btrfs, Zygo Blaxell, Josef Bacik, David Sterba,
	Sinnamohideen Shafeeq, Goffredo Baroncelli

On 1/5/22 03:29, Boris Burkov wrote:
> On Fri, Dec 17, 2021 at 07:47:04PM +0100, Goffredo Baroncelli wrote:
>> From: Goffredo Baroncelli <kreijack@inwind.it>
>>
>> Handle the property allocation_hint of a btrfs device. Below
>> an example of use:
>>
>> $ # set a new value
>> $ sudo btrfs property set /dev/vde allocation_hint DATA_ONLY
> 
> I applied this patchset to the master branch of
> git://github.com/kdave/btrfs-progs.git
> and this command failed with something like "not a btrfs object".
> 
> However, it worked fine as:
> $ sudo btrfs property set -t device /dev/DEV allocation_hint DATA_ONLY
> 
> I can't think of a reason I would hit this error and you wouldn't, since
> that check is relatively old, but figured I would mention it.

It seems that you missed the "failing command". However my guess is that this command fails on the LVM/DM devices, which often are link to the real devices.

Further investigation is needed.

BR

-- 
gpg @keyserver.linux.it: Goffredo Baroncelli <kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

end of thread, other threads:[~2022-01-05  9:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-17 18:47 [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2021-12-17 18:47 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
2022-01-05  2:29   ` Boris Burkov
2022-01-05  9:19     ` Goffredo Baroncelli
2021-12-17 18:47 ` [PATCH 2/2] Update man page for allocator_hint property Goffredo Baroncelli
2021-12-17 18:53 ` Script to test allocation_hint - [Was Re: [PATCH 0/2][V9] btrfs-progs: allocation_hint disk property] Goffredo Baroncelli
2021-12-21  5:36   ` Paul Jones
2021-12-21 20:58     ` Goffredo Baroncelli

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.