* [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property
@ 2022-01-06 17:49 Goffredo Baroncelli
2022-01-06 17:49 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Goffredo Baroncelli @ 2022-01-06 17:49 UTC (permalink / raw)
To: linux-btrfs
Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
Paul Jones, Boris Burkov, Goffredo Baroncelli
From: Goffredo Baroncelli <kreijack@inwind.it>
This patches set is the userspace portion of the serie
"[PATCH V10] 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 | 202 ++++++++++++++++++++++++++
kernel-shared/ctree.h | 13 ++
3 files changed, 232 insertions(+)
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/2] btrfs-progs: new "allocation_hint" property.
2022-01-06 17:49 [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
@ 2022-01-06 17:49 ` Goffredo Baroncelli
2022-01-06 17:49 ` [PATCH 2/2] Update man page for allocator_hint property Goffredo Baroncelli
2022-01-06 17:52 ` [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2 siblings, 0 replies; 10+ messages in thread
From: Goffredo Baroncelli @ 2022-01-06 17:49 UTC (permalink / raw)
To: linux-btrfs
Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
Paul Jones, Boris Burkov, 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
- DATA_PREFERRED (default)
- METADATA_PREFERRED
- METADATA_ONLY
Root privileges are required.
Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
cmds/property.c | 202 ++++++++++++++++++++++++++++++++++++++++++
kernel-shared/ctree.h | 13 +++
2 files changed, 215 insertions(+)
diff --git a/cmds/property.c b/cmds/property.c
index 59ef997c..1ac4266a 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,200 @@ 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_METADATA_PREFERRED, "METADATA_PREFERRED"},
+ {BTRFS_DEV_ALLOCATION_HINT_METADATA_ONLY, "METADATA_ONLY"},
+ {BTRFS_DEV_ALLOCATION_HINT_DATA_PREFERRED, "DATA_PREFERRED"},
+ {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 *val,
+ bool force)
+{
+ int ret, devid, fd, fd2 = -1;
+ 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;
+ 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;
+
+ if (!val) {
+ /* READ */
+ 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);
+ if (ret < 0) {
+ error("Unable to read the 'allocation_hint' property.");
+ ret = -errno;
+ goto out;
+ }
+
+ buf[sizeof(buf) - 1] = 0;
+ v = strtoull(buf, NULL, 0);
+
+ for (i = 0 ; allocation_hint_description[i].descr ; i++)
+ if (v == 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, v);
+ ret = 0;
+ } else {
+ /* WRITE */
+ for (i = 0 ; allocation_hint_description[i].descr ; i++)
+ if (!strcmp(val, allocation_hint_description[i].descr))
+ break;
+
+ if (allocation_hint_description[i].descr) {
+ v = allocation_hint_description[i].value;
+ } else if (sscanf(val, "%llu", &v) != 1) {
+ error("Invalid value '%s'\n", val);
+ ret = -3;
+ goto out;
+ }
+ if (v & ~BTRFS_DEV_ALLOCATION_HINT_MASK) {
+ error("Invalid value '%s'\n", val);
+ ret = -3;
+ goto out;
+ }
+
+ 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", v);
+
+ ret = write(fd2, buf, strlen(buf));
+
+ if (ret != strlen(buf)) {
+ error("Unable to update 'allocation_hint' property.");
+ ret = -errno;
+ goto out;
+ }
+
+ }
+
+ ret = 0;
+out:
+ if (fd2 >= 0)
+ close(fd2);
+ close_file_or_dir(fd, dir);
+ return ret;
+}
+
const struct prop_handler prop_handlers[] = {
{
.name ="ro",
@@ -254,6 +450,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 6ca49c09..597ad1af 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -216,6 +216,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_METADATA_PREFERRED (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_DATA_PREFERRED (0ULL)
+
#define BTRFS_UUID_SIZE 16
struct btrfs_dev_item {
/* the internal btrfs device id */
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/2] Update man page for allocator_hint property.
2022-01-06 17:49 [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2022-01-06 17:49 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
@ 2022-01-06 17:49 ` Goffredo Baroncelli
2022-01-06 17:52 ` [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2 siblings, 0 replies; 10+ messages in thread
From: Goffredo Baroncelli @ 2022-01-06 17:49 UTC (permalink / raw)
To: linux-btrfs
Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
Paul Jones, Boris Burkov, 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..70b01f68 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:
+- 'METADATA_PREFERRED': 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.
+- 'DATA_PREFERRED' (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 'DATA_PREFERRED'; 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] 10+ messages in thread
* Re: [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property
2022-01-06 17:49 [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2022-01-06 17:49 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
2022-01-06 17:49 ` [PATCH 2/2] Update man page for allocator_hint property Goffredo Baroncelli
@ 2022-01-06 17:52 ` Goffredo Baroncelli
2 siblings, 0 replies; 10+ messages in thread
From: Goffredo Baroncelli @ 2022-01-06 17:52 UTC (permalink / raw)
To: Goffredo Baroncelli, linux-btrfs
Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
Paul Jones, Boris Burkov
Below the script that I use to test this patch
----
#!/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() {
while losetup | egrep loop; do
umount $MNT
losetup -D
sleep 1s
done
}
raise() {
echo 1>&2 "$@"
exit 100
}
xmount() {
mount -o allocation_hint=1 "$1" "$2"
#mount "$1" "$2"
}
create_loops() {
[ -n "$1" ] || {
raise "Create_loops, missing an argument"
}
cleanup_all
size=$MAXSIZE
[ -n "$2" ] && size=$2
ret=""
for i in $(seq "$1"); do
disk=disk-$i.img
rm -rf $disk
truncate -s $size $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 }
'
}
# check if a disk conrain data and/or metadata
check_data_bg() {
res=$(dump_bg_data)
while [ -n "$1" ]; do
if ! echo $res | egrep -q $1 ; then
btrfs fil us $MNT
raise "Data BG should contains $1"
fi
shift
done
}
check_data_not_bg() {
res=$(dump_bg_data)
while [ -n "$1" ]; do
if echo $res | egrep -q $1 ; then
btrfs fil us $MNT
raise "Data BG should not contains $1"
fi
shift
done
}
check_metadata_bg() {
res=$(dump_bg_metadata)
while [ -n "$1" ]; do
if ! echo $res | egrep -q $1 ; then
btrfs fil us $MNT
raise "Metadata BG should contains $1"
fi
shift
done
}
check_metadata_not_bg() {
res=$(dump_bg_metadata)
while [ -n "$1" ]; do
if echo $res | egrep -q $1 ; then
btrfs fil us $MNT
raise "Metadata BG should not contains $1"
fi
shift
done
}
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)) )
check_data_bg $loop0 $loop1 $loop2 $loop3
#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)) )
check_data_bg $loop0 $loop1
#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 METADATA_PREFERRED
$BTRFS prop set $loop1 allocation_hint DATA_PREFERRED
$BTRFS balance start --full-balance $MNT
size=$(fill_1_file x $(($MAXSIZE / 2)) )
check_data_bg $loop1
check_data_not_bg $loop0
#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_slow() {
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_PREFERRED
$BTRFS prop set $loop1 allocation_hint DATA_PREFERRED
$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
check_metadata_bg $loop0
check_metadata_not_bg $loop1
#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 not 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 METADATA_PREFERRED
$BTRFS prop set $loop1 allocation_hint METADATA_PREFERRED
$BTRFS prop set $loop2 allocation_hint DATA_PREFERRED
$BTRFS prop set $loop3 allocation_hint DATA_PREFERRED
$BTRFS balance start --full-balance $MNT
size=$(fill_1_file x $(($MAXSIZE / 2)) )
check_data_bg $loop2 $loop3
check_data_not_bg $loop0 $loop1
#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_slow() {
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_PREFERRED
$BTRFS prop set $loop1 allocation_hint METADATA_PREFERRED
$BTRFS prop set $loop2 allocation_hint DATA_PREFERRED
$BTRFS prop set $loop3 allocation_hint DATA_PREFERRED
$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
check_metadata_bg $loop0 $loop1
check_metadata_not_bg $loop2 $loop3
#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 not contains $loop2"
#echo $res | egrep $loop3 &>/dev/null && raise "Metadata BG should not 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/"
check_data_bg $loop2 $loop3
check_data_not_bg $loop0 $loop1
#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/"
check_data_bg $loop1
check_data_not_bg $loop0
#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/"
check_data_bg $loop1
check_data_not_bg $loop0
#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
check_data_bg $loop1
check_data_not_bg $loop0
#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
check_data_bg $loop0
check_data_not_bg $loop1
#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
}
test_single_progressive_fill_data() {
xsize=$MAXSIZE
loops=$(create_loops 4 $xsize)
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 -dsingle -msingle $loops
xmount $loop0 $MNT
$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
$BTRFS prop set $loop1 allocation_hint METADATA_PREFERRED
$BTRFS prop set $loop2 allocation_hint DATA_PREFERRED
$BTRFS prop set $loop3 allocation_hint DATA_ONLY
$BTRFS balance start --full-balance $MNT
# fill $loop3
size=$(fill_1_file x $(( $xsize / 3 )))
for i in 1 2 3; do
check_data_bg $loop3
check_data_not_bg $loop1 $loop2 $loop0
$BTRFS balance start --full-balance $MNT
done
# fill $loop3 then $loop2
size=$(fill_1_file y $(( $xsize )))
for i in 1 2 3; do
check_data_bg $loop3 $loop2
check_data_not_bg $loop1 $loop0
$BTRFS balance start --full-balance $MNT
done
# fill $loop3 then $loop2, then $loop1
size=$(fill_1_file z $(( $xsize )))
for i in 1 2 3; do
check_data_bg $loop3 $loop2 $loop1
check_data_not_bg $loop0
$BTRFS balance start --full-balance $MNT
done
# fill the disk
size=$(fill_1_file w )
# when the disk is filled not balance is possible
check_data_bg $loop3 $loop2 $loop1
check_data_not_bg $loop0
cleanup_all
}
test_raid1_progressive_fill_data() {
xsize=$MAXSIZE
loops=$(create_loops 5 $xsize)
loop0=$(echo $loops | awk '{ print $1 }')
loop1=$(echo $loops | awk '{ print $2 }')
loop2=$(echo $loops | awk '{ print $3 }')
loop3=$(echo $loops | awk '{ print $4 }')
loop4=$(echo $loops | awk '{ print $5 }')
$BTRFS dev scan -u
mkfs.btrfs -U $UUID -dRAID1 -msingle $loops
xmount $loop0 $MNT
$BTRFS prop set $loop0 allocation_hint METADATA_ONLY
$BTRFS prop set $loop1 allocation_hint METADATA_PREFERRED
$BTRFS prop set $loop2 allocation_hint DATA_PREFERRED
$BTRFS prop set $loop3 allocation_hint DATA_ONLY
$BTRFS prop set $loop4 allocation_hint DATA_ONLY
$BTRFS balance start --full-balance $MNT
# fill $loop3 $loop4
size=$(fill_1_file x $(( $xsize / 6 )))
for i in 1 2 3; do
check_data_bg $loop3 $loop4
check_data_not_bg $loop1 $loop0 $loop2
$BTRFS balance start --full-balance $MNT
done
# fill $loop3, $loop4 then $loop2, $loop1
size=$(fill_1_file y $(( $xsize )))
for i in 1 2 3; do
check_data_bg $loop3 $loop2 $loop1 $loop4
check_data_not_bg $loop0
$BTRFS balance start --full-balance $MNT
done
cleanup_all
}
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
elif [ "$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
else
break
fi
done
cleanup_all &>/dev/null
cleanup_all &>/dev/null
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] 10+ messages in thread
* [PATCH 1/2] btrfs-progs: new "allocation_hint" property.
2022-03-06 18:15 [PATCH 0/2][V12] " Goffredo Baroncelli
@ 2022-03-06 18:15 ` Goffredo Baroncelli
0 siblings, 0 replies; 10+ messages in thread
From: Goffredo Baroncelli @ 2022-03-06 18:15 UTC (permalink / raw)
To: linux-btrfs
Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
Paul Jones, Boris Burkov, 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
- DATA_PREFERRED (default)
- METADATA_PREFERRED
- METADATA_ONLY
Root privileges are required.
Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
cmds/property.c | 162 ++++++++++++++++++++++++++++++++++++++++++
kernel-shared/ctree.h | 13 ++++
2 files changed, 175 insertions(+)
diff --git a/cmds/property.c b/cmds/property.c
index b3ccc0ff..b35c8ed3 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,160 @@ 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 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];
+ 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;
+
+ if (!value) {
+ /* READ */
+ printf("devid=%d, path=%s: allocation_hint=%s\n",
+ devid, object, buf);
+ ret = 0;
+ } else {
+ /* WRITE */
+ fd2 = open(sysfs_file, O_RDWR);
+ if (fd2 < 0) {
+ error("'allocation_hint' not accessible for updating.");
+ ret = -errno;
+ goto out;
+ }
+
+ ret = write(fd2, value, strlen(value));
+ close(fd2);
+ if (ret < 0) {
+ if (errno == EINVAL)
+ error("Invalid '%s' allocation_hint property.", value);
+ else
+ 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 +410,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 de5452f2..7bff3952 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -216,6 +216,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_METADATA_PREFERRED (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_DATA_PREFERRED (0ULL)
+
#define BTRFS_UUID_SIZE 16
struct btrfs_dev_item {
/* the internal btrfs device id */
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 1/2] btrfs-progs: new "allocation_hint" property.
2022-01-26 20:32 [PATCH 0/2][V11] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
@ 2022-01-26 20:32 ` Goffredo Baroncelli
0 siblings, 0 replies; 10+ messages in thread
From: Goffredo Baroncelli @ 2022-01-26 20:32 UTC (permalink / raw)
To: linux-btrfs
Cc: Zygo Blaxell, Josef Bacik, David Sterba, Sinnamohideen Shafeeq,
Paul Jones, Boris Burkov, 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
- DATA_PREFERRED (default)
- METADATA_PREFERRED
- METADATA_ONLY
Root privileges are required.
Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
cmds/property.c | 253 ++++++++++++++++++++++++++++++++++++++++++
kernel-shared/ctree.h | 13 +++
2 files changed, 266 insertions(+)
diff --git a/cmds/property.c b/cmds/property.c
index b3ccc0ff..a409f4e9 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"
@@ -232,6 +233,252 @@ out:
return ret;
}
+/*
+ * @major, @minor -> device to find
+ * @uuid -> uuid of the filesystem (out)
+ * @devid -> devid (out)
+ *
+ * return -> -ENOTSUP operation not supported (i.e. btrfs doesn't
+ * support allocation_hint)
+ * -> -ENODEV operation supported, but device not mounted
+ * -> -EACCES error accessing sysfs
+ * -> 0 ok
+ */
+#define BTRFSYSFS "/sys/fs/btrfs/"
+static int btrfs_find_devid_uuid_by_major_minor(int major,
+ int minor,
+ u64 *devid,
+ char *uuid) {
+
+ DIR *dp = NULL, *dp2 = NULL;
+ char path[200]; /* should be enough for
+ * /sys/btrfs/<uuid>/devices/<devid>/major_minor
+ */
+ int ret;
+ struct dirent *de;
+ int l;
+
+ strcpy(path, BTRFSYSFS);
+ dp = opendir(path);
+ if (!dp) {
+ ret = -EACCES;
+ goto quit;
+ }
+
+ while ((de = readdir(dp)) != NULL) {
+ if (strlen(de->d_name) != 36)
+ continue;
+
+ strcpy(path + sizeof(BTRFSYSFS) - 1, de->d_name);
+ strcat(path, "/devinfo/");
+
+ dp2 = opendir(path);
+ if (!dp2) {
+ ret = -EACCES;
+ goto quit;
+ }
+
+ l = strlen(path);
+ while ((de = readdir(dp2)) != NULL) {
+ FILE *fp;
+ char buf[100];
+ char *endptr;
+ int r, maj, mnr;
+
+ errno = 0;
+ *devid = strtoull(de->d_name, &endptr, 0);
+
+ /* check for invalid devid */
+ if (errno || *endptr != 0)
+ continue;
+
+
+ strcpy(path + l, de->d_name);
+ strcat(path, "/major_minor");
+
+ fp = fopen(path, "r");
+ if (!fp) {
+ if (errno == -ENOENT)
+ ret = -ENOTSUP;
+ else
+ ret = -EACCES;
+ goto quit;
+ }
+ r = fread(buf, 1, sizeof(buf) - 2, fp);
+ buf[r] = 0;
+ fclose(fp);
+
+ if (!strcmp(buf, "N/A\n"))
+ continue;
+
+ r = sscanf(buf, "%d:%d", &maj, &mnr);
+ if (r != 2) {
+ ret = -EACCES;
+ goto quit;
+ }
+
+ if (maj == major && minor == mnr) {
+ strncpy(uuid,
+ path + sizeof(BTRFSYSFS) - 1,
+ 36);
+ uuid[36] = 0;
+ ret = 0;
+ goto quit;
+ }
+ }
+ }
+
+ ret = -ENODEV;
+quit:
+ if (dp)
+ closedir(dp);
+ if (dp2)
+ closedir(dp2);
+ return ret;
+}
+
+/*
+ * @dev -> device to find
+ * @uuid -> uuid of the filesystem (out)
+ * @devid -> devid (out)
+ *
+ * return -> -ENOTSUP operation not supported (i.e. btrfs doesn't
+ * support allocation_hint)
+ * -> -ENODEV operation supported, but device not mounted
+ * -> -EACCES error accessing sysfs
+ * -> 0 ok
+ */
+static int btrfs_find_devid_uuid_by_dev(const char *dev,
+ u64 *devid,
+ char *uuid)
+{
+ struct stat st;
+ int r;
+
+ r = stat(dev, &st);
+ if (r < 0 && errno == -ENODEV)
+ return -ENODEV;
+ if (r < 0)
+ return -EACCES;
+
+ return btrfs_find_devid_uuid_by_major_minor(major(st.st_rdev),
+ minor(st.st_rdev),
+ devid, uuid);
+}
+
+static struct ull_charp_pair_t {
+ u64 value;
+ const char *descr;
+} allocation_hint_description[] = {
+ {BTRFS_DEV_ALLOCATION_HINT_METADATA_PREFERRED, "METADATA_PREFERRED"},
+ {BTRFS_DEV_ALLOCATION_HINT_METADATA_ONLY, "METADATA_ONLY"},
+ {BTRFS_DEV_ALLOCATION_HINT_DATA_PREFERRED, "DATA_PREFERRED"},
+ {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 *val,
+ bool force)
+{
+ int ret, fd2 = -1;
+ u64 devid;
+ char sysfs_file[PATH_MAX];
+ int i;
+ u64 v;
+ char buf[1024];
+
+ strcpy(sysfs_file, BTRFSYSFS);
+ ret = btrfs_find_devid_uuid_by_dev(object, &devid,
+ sysfs_file + sizeof(BTRFSYSFS) - 1);
+
+ if (ret)
+ goto out;
+
+ sprintf(sysfs_file + strlen(sysfs_file),
+ "/devinfo/%llu/allocation_hint", devid);
+
+ if (!val) {
+ /* READ */
+ fd2 = open(sysfs_file, O_RDONLY);
+ if (fd2 < 0 && errno == ENOENT) {
+ /* older kernel doesn't have allocation_hint; return nothing */
+ ret = 0;
+ goto out;
+ } else if (fd2 < 0) {
+ error("'allocation_hint' property not available or accessible.");
+ ret = -errno;
+ goto out;
+ }
+
+ ret = read(fd2, buf, sizeof(buf) - 1);
+ if (ret < 0) {
+ error("Unable to read the 'allocation_hint' property.");
+ ret = -errno;
+ goto out;
+ }
+
+ buf[sizeof(buf) - 1] = 0;
+ v = strtoull(buf, NULL, 0);
+
+ for (i = 0 ; allocation_hint_description[i].descr ; i++)
+ if (v == allocation_hint_description[i].value)
+ break;
+
+ if (allocation_hint_description[i].descr)
+ printf("allocation_hint=%s\n",
+ allocation_hint_description[i].descr);
+ else
+ printf("allocation_hint=unknown:%llu\n", v);
+ ret = 0;
+ } else {
+ /* WRITE */
+ for (i = 0 ; allocation_hint_description[i].descr ; i++)
+ if (!strcmp(val, allocation_hint_description[i].descr))
+ break;
+
+ if (allocation_hint_description[i].descr) {
+ v = allocation_hint_description[i].value;
+ } else if (sscanf(val, "%llu", &v) != 1) {
+ error("Invalid value '%s'\n", val);
+ ret = -3;
+ goto out;
+ }
+ if (v & ~BTRFS_DEV_ALLOCATION_HINT_MASK) {
+ error("Invalid value '%s'\n", val);
+ ret = -3;
+ goto out;
+ }
+
+ 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", v);
+
+ ret = write(fd2, buf, strlen(buf));
+
+ if (ret != strlen(buf)) {
+ error("Unable to update 'allocation_hint' property.");
+ ret = -errno;
+ goto out;
+ }
+
+ }
+
+ ret = 0;
+out:
+ if (fd2 >= 0)
+ close(fd2);
+
+ return ret;
+}
+
const struct prop_handler prop_handlers[] = {
{
.name ="ro",
@@ -254,6 +501,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 ab2aaed6..628539c0 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -216,6 +216,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_METADATA_PREFERRED (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_DATA_PREFERRED (0ULL)
+
#define BTRFS_UUID_SIZE 16
struct btrfs_dev_item {
/* the internal btrfs device id */
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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
0 siblings, 1 reply; 10+ 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] 10+ messages in thread
* [PATCH 1/2] btrfs-progs: new "allocation_hint" property.
2021-10-24 15:31 [PATCH 0/2][V8] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
@ 2021-10-24 15:31 ` Goffredo Baroncelli
0 siblings, 0 replies; 10+ messages in thread
From: Goffredo Baroncelli @ 2021-10-24 15:31 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 | 199 ++++++++++++++++++++++++++++++++++++++++++
kernel-shared/ctree.h | 14 +++
2 files changed, 213 insertions(+)
diff --git a/cmds/property.c b/cmds/property.c
index 59ef997c..5abd8f03 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,197 @@ 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_PREFERRED_METADATA, "PREFERRED_METADATA"},
+ {BTRFS_DEV_ALLOCATION_METADATA_ONLY, "METADATA_ONLY"},
+ {BTRFS_DEV_ALLOCATION_PREFERRED_DATA, "PREFERRED_DATA"},
+ {BTRFS_DEV_ALLOCATION_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/type", 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) {
+ ret = -errno;
+ goto out;
+ }
+
+ ret = read(fd2, buf, sizeof(buf) - 1);
+ close(fd2);
+ if (ret < 0) {
+ 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;
+ } else if (v & ~BTRFS_DEV_ALLOCATION_MASK) {
+ error("Invalid value '%s'\n", value);
+ ret = -3;
+ goto out;
+ }
+
+ devtype &= ~BTRFS_DEV_ALLOCATION_MASK;
+ devtype |= (v & BTRFS_DEV_ALLOCATION_MASK);
+
+ fd2 = open(sysfs_file, O_RDWR);
+ if (fd2 < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ sprintf(buf, "%llu", devtype);
+
+ ret = write(fd2, buf, strlen(buf));
+ close(fd2);
+ if (ret < 0) {
+ 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 +447,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 5f616585..d4635d13 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -219,6 +219,20 @@ struct btrfs_mapping_tree {
struct cache_tree cache_tree;
};
+/* btrfs chunk allocation hints */
+#define BTRFS_DEV_ALLOCATION_MASK_BIT_COUNT 3
+#define BTRFS_DEV_ALLOCATION_MASK ((1ULL << \
+ BTRFS_DEV_ALLOCATION_MASK_BIT_COUNT) - 1)
+/* preferred metadata chunk, but data chunk allowed */
+#define BTRFS_DEV_ALLOCATION_PREFERRED_METADATA (1ULL)
+/* only metadata chunk are allowed */
+#define BTRFS_DEV_ALLOCATION_METADATA_ONLY (2ULL)
+/* only data chunk allowed */
+#define BTRFS_DEV_ALLOCATION_DATA_ONLY (3ULL)
+/* preferred data chunk, but metadata chunk allowed */
+#define BTRFS_DEV_ALLOCATION_PREFERRED_DATA (0ULL)
+/* 5..7 are unused values */
+
#define BTRFS_UUID_SIZE 16
struct btrfs_dev_item {
/* the internal btrfs device id */
--
2.33.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2022-03-06 18:16 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-06 17:49 [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2022-01-06 17:49 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
2022-01-06 17:49 ` [PATCH 2/2] Update man page for allocator_hint property Goffredo Baroncelli
2022-01-06 17:52 ` [PATCH 0/2][V10] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
-- strict thread matches above, loose matches on Subject: below --
2022-03-06 18:15 [PATCH 0/2][V12] " Goffredo Baroncelli
2022-03-06 18:15 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
2022-01-26 20:32 [PATCH 0/2][V11] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2022-01-26 20:32 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
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-10-24 15:31 [PATCH 0/2][V8] btrfs-progs: allocation_hint disk property Goffredo Baroncelli
2021-10-24 15:31 ` [PATCH 1/2] btrfs-progs: new "allocation_hint" property Goffredo Baroncelli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).