* [PATCH v4 0/3] btrfs-progs: Fix logical-resolve
@ 2020-11-27 19:30 Marcos Paulo de Souza
2020-11-27 19:30 ` [PATCH v4 1/3] btrfs-progs: Adapt find_mount_root to verify other fields of mntent struct Marcos Paulo de Souza
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Marcos Paulo de Souza @ 2020-11-27 19:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Marcos Paulo de Souza, wqu, dsterba
From: Marcos Paulo de Souza <mpdesouza@suse.com>
In this forth iteration, only patch 0002 was changed. Previously the variable
full_path, which is passed by the user, was being overwritten in the inode loop.
Now we create a temp var to store the mount_point when the lookup is needed.
Please review.
Changes from v3:
* In patch 0002, do not overwrite full_path variable
Changes from v2:
* Make mnt_opts check more strict to avoid bind mounts (Qu)
* Print only inode/subvolume when the subvolume itself is not mounted
* Enhance the test by adding a snapshot (unmounted) to exercise the check above
* Enhance the test by adding a bind mount that would trick logical-resolve
Changes from v1:
* Patches 2 and 3 added
* Test created (David)
* Discard changed on btrfs_list_path_for_root and changing find_mount_root
instead
Marcos Paulo de Souza (3):
btrfs-progs: Adapt find_mount_root to verify other fields of mntent
struct
btrfs-progs: inspect: Fix logical-resolve file path lookup
btrfs-progs: tests: Add new logical-resolve test
cmds/inspect.c | 44 +++++++---
cmds/receive.c | 3 +-
cmds/send.c | 6 +-
common/utils.c | 32 +++++++-
common/utils.h | 11 ++-
.../test.sh | 81 +++++++++++++++++++
6 files changed, 160 insertions(+), 17 deletions(-)
create mode 100755 tests/misc-tests/042-inspect-internal-logical-resolve/test.sh
--
2.26.2
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 1/3] btrfs-progs: Adapt find_mount_root to verify other fields of mntent struct
2020-11-27 19:30 [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Marcos Paulo de Souza
@ 2020-11-27 19:30 ` Marcos Paulo de Souza
2020-11-27 19:30 ` [PATCH v4 2/3] btrfs-progs: inspect: Fix logical-resolve file path lookup Marcos Paulo de Souza
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Marcos Paulo de Souza @ 2020-11-27 19:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Marcos Paulo de Souza, wqu, dsterba
From: Marcos Paulo de Souza <mpdesouza@suse.com>
Currently find_mount_root searches for all btrfs filesystems
mounted and comparing <path> with mnt_dir of each mountpoint.
But there are cases when we need to find the mountpoint for a determined
subvolid or subvol path, and these informations are present in mnt_opts
of mntent struct.
This patch adds two arguments to find_mount_root (data and flag). The
data argument hold the information that we want to compare, and the flag
argument specifies which field of mntent struct that we want to compare.
Currently there is only one flag, BTRFS_FIND_ROOT_PATH, implementing the
current behavior. The next patch will add a new flag to expand the functionality.
Users of find_mount_root were changed, having the data argument the same
as path, since they are only trying to find the mountpoint based on path alone.
Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
cmds/receive.c | 3 ++-
cmds/send.c | 6 ++++--
common/utils.c | 15 ++++++++++++---
common/utils.h | 8 +++++++-
4 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/cmds/receive.c b/cmds/receive.c
index 2aaba3ff..dc64480e 100644
--- a/cmds/receive.c
+++ b/cmds/receive.c
@@ -1079,7 +1079,8 @@ static int do_receive(struct btrfs_receive *rctx, const char *tomnt,
if (realmnt[0]) {
rctx->root_path = realmnt;
} else {
- ret = find_mount_root(dest_dir_full_path, &rctx->root_path);
+ ret = find_mount_root(dest_dir_full_path, dest_dir_full_path,
+ BTRFS_FIND_ROOT_PATH, &rctx->root_path);
if (ret < 0) {
errno = -ret;
error("failed to determine mount point for %s: %m",
diff --git a/cmds/send.c b/cmds/send.c
index b8e3ba12..7757f0da 100644
--- a/cmds/send.c
+++ b/cmds/send.c
@@ -329,7 +329,8 @@ static int init_root_path(struct btrfs_send *sctx, const char *subvol)
if (sctx->root_path)
goto out;
- ret = find_mount_root(subvol, &sctx->root_path);
+ ret = find_mount_root(subvol, subvol, BTRFS_FIND_ROOT_PATH,
+ &sctx->root_path);
if (ret < 0) {
errno = -ret;
error("failed to determine mount point for %s: %m", subvol);
@@ -659,7 +660,8 @@ static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)
goto out;
}
- ret = find_mount_root(subvol, &mount_root);
+ ret = find_mount_root(subvol, subvol, BTRFS_FIND_ROOT_PATH,
+ &mount_root);
if (ret < 0) {
errno = -ret;
error("find_mount_root failed on %s: %m", subvol);
diff --git a/common/utils.c b/common/utils.c
index 1253e87d..1c264455 100644
--- a/common/utils.c
+++ b/common/utils.c
@@ -1248,7 +1248,7 @@ int ask_user(const char *question)
* return 1 if a mount point is found but not btrfs
* return <0 if something goes wrong
*/
-int find_mount_root(const char *path, char **mount_root)
+int find_mount_root(const char *path, const char *data, u8 flag, char **mount_root)
{
FILE *mnttab;
int fd;
@@ -1258,6 +1258,10 @@ int find_mount_root(const char *path, char **mount_root)
int not_btrfs = 1;
int longest_matchlen = 0;
char *longest_match = NULL;
+ char *cmp_field = NULL;
+ bool found;
+
+ BUG_ON(flag != BTRFS_FIND_ROOT_PATH);
fd = open(path, O_RDONLY | O_NOATIME);
if (fd < 0)
@@ -1269,8 +1273,13 @@ int find_mount_root(const char *path, char **mount_root)
return -errno;
while ((ent = getmntent(mnttab))) {
- len = strlen(ent->mnt_dir);
- if (strncmp(ent->mnt_dir, path, len) == 0) {
+ cmp_field = ent->mnt_dir;
+
+ len = strlen(cmp_field);
+
+ found = strncmp(cmp_field, data, len) == 0;
+
+ if (found) {
/* match found and use the latest match */
if (longest_matchlen <= len) {
free(longest_match);
diff --git a/common/utils.h b/common/utils.h
index 119c3881..449e1d3e 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -52,6 +52,11 @@
#define UNITS_HUMAN (UNITS_HUMAN_BINARY)
#define UNITS_DEFAULT (UNITS_HUMAN)
+enum btrfs_find_root_flags {
+ /* check mnt_dir of mntent */
+ BTRFS_FIND_ROOT_PATH = 0
+};
+
void units_set_mode(unsigned *units, unsigned mode);
void units_set_base(unsigned *units, unsigned base);
@@ -93,7 +98,8 @@ int csum_tree_block(struct btrfs_fs_info *root, struct extent_buffer *buf,
int ask_user(const char *question);
int lookup_path_rootid(int fd, u64 *rootid);
int get_btrfs_mount(const char *dev, char *mp, size_t mp_size);
-int find_mount_root(const char *path, char **mount_root);
+int find_mount_root(const char *path, const char *data, u8 flag,
+ char **mount_root);
int get_device_info(int fd, u64 devid,
struct btrfs_ioctl_dev_info_args *di_args);
int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret);
--
2.26.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 2/3] btrfs-progs: inspect: Fix logical-resolve file path lookup
2020-11-27 19:30 [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Marcos Paulo de Souza
2020-11-27 19:30 ` [PATCH v4 1/3] btrfs-progs: Adapt find_mount_root to verify other fields of mntent struct Marcos Paulo de Souza
@ 2020-11-27 19:30 ` Marcos Paulo de Souza
2020-12-04 0:08 ` Qu Wenruo
2020-11-27 19:30 ` [PATCH v4 3/3] btrfs-progs: tests: Add new logical-resolve test Marcos Paulo de Souza
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Marcos Paulo de Souza @ 2020-11-27 19:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Marcos Paulo de Souza, wqu, dsterba
From: Marcos Paulo de Souza <mpdesouza@suse.com>
[BUG]
logical-resolve is currently broken on systems that have a child
subvolume being mounted without access to the parent subvolume.
This is the default for SLE/openSUSE installations. openSUSE has the
subvolume '@' as the parent of all other subvolumes like /boot, /home.
The subvolume '@' is never mounted and accessed, but only it's childs:
mount | grep btrfs
/dev/sda2 on / type btrfs (rw,relatime,ssd,space_cache,subvolid=267,subvol=/@/.snapshots/1/snapshot)
/dev/sda2 on /opt type btrfs (rw,relatime,ssd,space_cache,subvolid=262,subvol=/@/opt)
/dev/sda2 on /boot/grub2/i386-pc type btrfs (rw,relatime,ssd,space_cache,subvolid=265,subvol=/@/boot/grub2/i386-pc)
logical-resolve command calls btrfs_list_path_for_root, that returns the
subvolume full-path that corresponds to the tree id of the logical
address. As the name implies, the 'full-path' returns the subvolume full
path, starting from '@'. Later on, btrfs_open_dir is called using the path
returned, but it fails to resolve it since it contains the '@' and this
subvolume cannot be accessed.
The same problem can be triggered to any user that calls for
logical-resolve on a child subvolume that has the parent subvolume
not accessible.
Another problem in the current approach is that it believes that a
subvolume will be mounted in a directory with the same name e.g /@/boot
being mounted in /boot. When this is not true, the code also fails,
since it uses the subvolume name as the path.
[FIX]
Extent the find_mount_root function by allowing it to check for mnt_opts
member of mntent struct. Using this new approach we can change
logical-resolve command to search for subvolid=XXX,subvol=YYY returning
the correct path accessible to the user. Using this approach we can solve
the problems stated above by not trusting the subvolume name being the
mountpoint, and not executing the lookup based only in the subvolume
tree.
Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
cmds/inspect.c | 44 ++++++++++++++++++++++++++++++++++----------
common/utils.c | 29 +++++++++++++++++++++++------
common/utils.h | 5 ++++-
3 files changed, 61 insertions(+), 17 deletions(-)
diff --git a/cmds/inspect.c b/cmds/inspect.c
index 2530b904..cfa2f708 100644
--- a/cmds/inspect.c
+++ b/cmds/inspect.c
@@ -236,6 +236,7 @@ static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
DIR *dirs = NULL;
if (getpath) {
+ char mount_path[PATH_MAX];
name = btrfs_list_path_for_root(fd, root);
if (IS_ERR(name)) {
ret = PTR_ERR(name);
@@ -244,23 +245,46 @@ static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
if (!name) {
path_ptr[-1] = '\0';
path_fd = fd;
+
+ strncpy(mount_path, full_path, PATH_MAX);
} else {
- path_ptr[-1] = '/';
- ret = snprintf(path_ptr, bytes_left, "%s",
- name);
- free(name);
- if (ret >= bytes_left) {
- error("path buffer too small: %d bytes",
- bytes_left - ret);
- goto out;
+ char *mounted = NULL;
+ char volid_str[PATH_MAX];
+
+ /*
+ * btrfs_list_path_for_root returns the full
+ * path to the subvolume pointed by root, but the
+ * subvolume can be mounted in a directory name
+ * different from the subvolume name. In this
+ * case we need to find the correct mountpoint
+ * using same subvol path and subvol id found
+ * before.
+ */
+ snprintf(volid_str, PATH_MAX, "subvolid=%llu,subvol=/%s",
+ root, name);
+
+ ret = find_mount_root(full_path, volid_str,
+ BTRFS_FIND_ROOT_OPTS, &mounted);
+
+ if (ret == -ENOENT) {
+ printf("inode %llu subvol %s could not be accessed: not mounted\n",
+ inum, name);
+ continue;
}
- path_fd = btrfs_open_dir(full_path, &dirs, 1);
+
+ if (ret < 0)
+ goto out;
+
+ strncpy(mount_path, mounted, PATH_MAX);
+ free(mounted);
+
+ path_fd = btrfs_open_dir(mount_path, &dirs, 1);
if (path_fd < 0) {
ret = -ENOENT;
goto out;
}
}
- ret = __ino_to_path_fd(inum, path_fd, full_path);
+ ret = __ino_to_path_fd(inum, path_fd, mount_path);
if (path_fd != fd)
close_file_or_dir(path_fd, dirs);
} else {
diff --git a/common/utils.c b/common/utils.c
index 1c264455..1562ac52 100644
--- a/common/utils.c
+++ b/common/utils.c
@@ -1259,9 +1259,6 @@ int find_mount_root(const char *path, const char *data, u8 flag, char **mount_ro
int longest_matchlen = 0;
char *longest_match = NULL;
char *cmp_field = NULL;
- bool found;
-
- BUG_ON(flag != BTRFS_FIND_ROOT_PATH);
fd = open(path, O_RDONLY | O_NOATIME);
if (fd < 0)
@@ -1273,12 +1270,32 @@ int find_mount_root(const char *path, const char *data, u8 flag, char **mount_ro
return -errno;
while ((ent = getmntent(mnttab))) {
- cmp_field = ent->mnt_dir;
+ bool found = false;
- len = strlen(cmp_field);
+ /* BTRFS_FIND_ROOT_PATH is the default behavior */
+ if (flag == BTRFS_FIND_ROOT_OPTS)
+ cmp_field = ent->mnt_opts;
+ else
+ cmp_field = ent->mnt_dir;
- found = strncmp(cmp_field, data, len) == 0;
+ len = strlen(cmp_field);
+ if (flag == BTRFS_FIND_ROOT_OPTS) {
+ size_t dlen = strlen(data);
+ char *tmp_str = strstr(cmp_field, data);
+ /*
+ * Make sure that we are dealing with the wanted string,
+ * since strstr returns the start of the string found.
+ * Compare the end string position from data with the
+ * mount point found, and make sure that we have an
+ * option separator or string end.
+ */
+ if (tmp_str)
+ found = tmp_str[dlen] == ',' ||
+ tmp_str[dlen] == 0;
+ } else {
+ found = strncmp(cmp_field, data, len) == 0;
+ }
if (found) {
/* match found and use the latest match */
if (longest_matchlen <= len) {
diff --git a/common/utils.h b/common/utils.h
index 449e1d3e..b5d256c6 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -54,7 +54,10 @@
enum btrfs_find_root_flags {
/* check mnt_dir of mntent */
- BTRFS_FIND_ROOT_PATH = 0
+ BTRFS_FIND_ROOT_PATH = 0,
+
+ /* check mnt_opts of mntent */
+ BTRFS_FIND_ROOT_OPTS
};
void units_set_mode(unsigned *units, unsigned mode);
--
2.26.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 3/3] btrfs-progs: tests: Add new logical-resolve test
2020-11-27 19:30 [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Marcos Paulo de Souza
2020-11-27 19:30 ` [PATCH v4 1/3] btrfs-progs: Adapt find_mount_root to verify other fields of mntent struct Marcos Paulo de Souza
2020-11-27 19:30 ` [PATCH v4 2/3] btrfs-progs: inspect: Fix logical-resolve file path lookup Marcos Paulo de Souza
@ 2020-11-27 19:30 ` Marcos Paulo de Souza
2020-12-02 20:12 ` [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Josef Bacik
2021-01-14 18:42 ` David Sterba
4 siblings, 0 replies; 7+ messages in thread
From: Marcos Paulo de Souza @ 2020-11-27 19:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Marcos Paulo de Souza, wqu, dsterba
From: Marcos Paulo de Souza <mpdesouza@suse.com>
Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
---
.../test.sh | 81 +++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100755 tests/misc-tests/042-inspect-internal-logical-resolve/test.sh
diff --git a/tests/misc-tests/042-inspect-internal-logical-resolve/test.sh b/tests/misc-tests/042-inspect-internal-logical-resolve/test.sh
new file mode 100755
index 00000000..fcf1147f
--- /dev/null
+++ b/tests/misc-tests/042-inspect-internal-logical-resolve/test.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+# Check if logical-resolve is resolving the paths correctly for different
+# subvolume tree configurations. This used to fail when a child subvolume was
+# mounted without the parent subvolume being accessible.
+
+source "$TEST_TOP/common"
+
+setup_root_helper
+prepare_test_dev
+
+check_prereq btrfs
+check_prereq mkfs.btrfs
+
+check_logical_offset_filename()
+{
+ local filename
+ local offset
+ offset="$1"
+ filename="$2"
+
+ while read file; do
+ if [[ "$file" = *"inode "* ]]; then
+ _log "$file"
+ elif [ ! -f $file ]; then
+ _fail "Path not $file file cannot be accessed"
+ elif [ ! $filename = $file ]; then
+ _fail "logical-resolve failed. Expected $filename but returned $file"
+ else
+ _log "$file"
+ fi
+ done < <($TOP/btrfs inspect-internal logical-resolve "$offset" "$TEST_MNT")
+}
+
+run_check_mkfs_test_dev
+run_check_mount_test_dev
+
+# create top subvolume called '@'
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume create "$TEST_MNT/@"
+
+# create a file in eacch subvolume of @, and each file will have 2 EXTENT_DATA
+# items, and also create a snapshot to have a extent being referenced by two
+# different fs trees
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume create "$TEST_MNT/@/vol1"
+vol1id=$($SUDO_HELPER "$TOP/btrfs" inspect-internal rootid "$TEST_MNT/@/vol1")
+run_check $SUDO_HELPER dd if=/dev/zero bs=1M count=150 of="$TEST_MNT/@/vol1/file1"
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume snapshot "$TEST_MNT/@/vol1" "$TEST_MNT/@/snap1"
+
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume create "$TEST_MNT/@/vol1/subvol1"
+subvol1id=$($SUDO_HELPER "$TOP/btrfs" inspect-internal rootid "$TEST_MNT/@/vol1/subvol1")
+run_check $SUDO_HELPER dd if=/dev/zero bs=1M count=150 of="$TEST_MNT/@/vol1/subvol1/file2"
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume snapshot "$TEST_MNT/@/vol1/subvol1" \
+ "$TEST_MNT/@/vol1/snapshot1"
+
+"$TOP/btrfs" filesystem sync "$TEST_MNT"
+
+run_check_umount_test_dev
+
+# to be used later
+mkdir -p mnt2
+
+$SUDO_HELPER mount -o subvol=/@/vol1 $TEST_DEV "$TEST_MNT"
+# create a bind mount to the vol1. logical-resolve should avoid bind mounts,
+# otherwise the test will fail
+mkdir -p "$TEST_MNT/dir"
+$SUDO_HELPER mount --bind "$TEST_MNT/dir" mnt2
+
+for offset in $("$TOP/btrfs" inspect-internal dump-tree -t "$vol1id" \
+ "$TEST_DEV" | awk '/disk byte/ { print $5 }'); do
+ check_logical_offset_filename "$offset" "$TEST_MNT/file1"
+done
+
+run_check_umount_test_dev mnt2
+run_check_umount_test_dev
+
+$SUDO_HELPER mount -o subvol=/@/vol1/subvol1 $TEST_DEV "$TEST_MNT"
+for offset in $("$TOP/btrfs" inspect-internal dump-tree -t "$subvol1id" \
+ "$TEST_DEV" | awk '/disk byte/ { print $5 }'); do
+ check_logical_offset_filename "$offset" "$TEST_MNT/file2"
+done
+
+run_check_umount_test_dev
--
2.26.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v4 0/3] btrfs-progs: Fix logical-resolve
2020-11-27 19:30 [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Marcos Paulo de Souza
` (2 preceding siblings ...)
2020-11-27 19:30 ` [PATCH v4 3/3] btrfs-progs: tests: Add new logical-resolve test Marcos Paulo de Souza
@ 2020-12-02 20:12 ` Josef Bacik
2021-01-14 18:42 ` David Sterba
4 siblings, 0 replies; 7+ messages in thread
From: Josef Bacik @ 2020-12-02 20:12 UTC (permalink / raw)
To: Marcos Paulo de Souza, linux-btrfs; +Cc: Marcos Paulo de Souza, wqu, dsterba
On 11/27/20 2:30 PM, Marcos Paulo de Souza wrote:
> From: Marcos Paulo de Souza <mpdesouza@suse.com>
>
> In this forth iteration, only patch 0002 was changed. Previously the variable
> full_path, which is passed by the user, was being overwritten in the inode loop.
> Now we create a temp var to store the mount_point when the lookup is needed.
>
> Please review.
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Thanks,
Josef
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 2/3] btrfs-progs: inspect: Fix logical-resolve file path lookup
2020-11-27 19:30 ` [PATCH v4 2/3] btrfs-progs: inspect: Fix logical-resolve file path lookup Marcos Paulo de Souza
@ 2020-12-04 0:08 ` Qu Wenruo
0 siblings, 0 replies; 7+ messages in thread
From: Qu Wenruo @ 2020-12-04 0:08 UTC (permalink / raw)
To: Marcos Paulo de Souza, linux-btrfs; +Cc: Marcos Paulo de Souza, wqu, dsterba
[-- Attachment #1.1: Type: text/plain, Size: 6889 bytes --]
On 2020/11/28 上午3:30, Marcos Paulo de Souza wrote:
> From: Marcos Paulo de Souza <mpdesouza@suse.com>
>
> [BUG]
> logical-resolve is currently broken on systems that have a child
> subvolume being mounted without access to the parent subvolume.
> This is the default for SLE/openSUSE installations. openSUSE has the
> subvolume '@' as the parent of all other subvolumes like /boot, /home.
> The subvolume '@' is never mounted and accessed, but only it's childs:
>
> mount | grep btrfs
> /dev/sda2 on / type btrfs (rw,relatime,ssd,space_cache,subvolid=267,subvol=/@/.snapshots/1/snapshot)
> /dev/sda2 on /opt type btrfs (rw,relatime,ssd,space_cache,subvolid=262,subvol=/@/opt)
> /dev/sda2 on /boot/grub2/i386-pc type btrfs (rw,relatime,ssd,space_cache,subvolid=265,subvol=/@/boot/grub2/i386-pc)
>
> logical-resolve command calls btrfs_list_path_for_root, that returns the
> subvolume full-path that corresponds to the tree id of the logical
> address. As the name implies, the 'full-path' returns the subvolume full
> path, starting from '@'. Later on, btrfs_open_dir is called using the path
> returned, but it fails to resolve it since it contains the '@' and this
> subvolume cannot be accessed.
>
> The same problem can be triggered to any user that calls for
> logical-resolve on a child subvolume that has the parent subvolume
> not accessible.
>
> Another problem in the current approach is that it believes that a
> subvolume will be mounted in a directory with the same name e.g /@/boot
> being mounted in /boot. When this is not true, the code also fails,
> since it uses the subvolume name as the path.
>
> [FIX]
> Extent the find_mount_root function by allowing it to check for mnt_opts
> member of mntent struct. Using this new approach we can change
> logical-resolve command to search for subvolid=XXX,subvol=YYY returning
> the correct path accessible to the user. Using this approach we can solve
> the problems stated above by not trusting the subvolume name being the
> mountpoint, and not executing the lookup based only in the subvolume
> tree.
>
> Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
With the extra prompt for subvolume can't be accessed, it looks good to
me now.
Reviewed-by: Qu Wenruo <wqu@suse.com>
Thanks,
Qu
> ---
> cmds/inspect.c | 44 ++++++++++++++++++++++++++++++++++----------
> common/utils.c | 29 +++++++++++++++++++++++------
> common/utils.h | 5 ++++-
> 3 files changed, 61 insertions(+), 17 deletions(-)
>
> diff --git a/cmds/inspect.c b/cmds/inspect.c
> index 2530b904..cfa2f708 100644
> --- a/cmds/inspect.c
> +++ b/cmds/inspect.c
> @@ -236,6 +236,7 @@ static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
> DIR *dirs = NULL;
>
> if (getpath) {
> + char mount_path[PATH_MAX];
> name = btrfs_list_path_for_root(fd, root);
> if (IS_ERR(name)) {
> ret = PTR_ERR(name);
> @@ -244,23 +245,46 @@ static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
> if (!name) {
> path_ptr[-1] = '\0';
> path_fd = fd;
> +
> + strncpy(mount_path, full_path, PATH_MAX);
> } else {
> - path_ptr[-1] = '/';
> - ret = snprintf(path_ptr, bytes_left, "%s",
> - name);
> - free(name);
> - if (ret >= bytes_left) {
> - error("path buffer too small: %d bytes",
> - bytes_left - ret);
> - goto out;
> + char *mounted = NULL;
> + char volid_str[PATH_MAX];
> +
> + /*
> + * btrfs_list_path_for_root returns the full
> + * path to the subvolume pointed by root, but the
> + * subvolume can be mounted in a directory name
> + * different from the subvolume name. In this
> + * case we need to find the correct mountpoint
> + * using same subvol path and subvol id found
> + * before.
> + */
> + snprintf(volid_str, PATH_MAX, "subvolid=%llu,subvol=/%s",
> + root, name);
> +
> + ret = find_mount_root(full_path, volid_str,
> + BTRFS_FIND_ROOT_OPTS, &mounted);
> +
> + if (ret == -ENOENT) {
> + printf("inode %llu subvol %s could not be accessed: not mounted\n",
> + inum, name);
> + continue;
> }
> - path_fd = btrfs_open_dir(full_path, &dirs, 1);
> +
> + if (ret < 0)
> + goto out;
> +
> + strncpy(mount_path, mounted, PATH_MAX);
> + free(mounted);
> +
> + path_fd = btrfs_open_dir(mount_path, &dirs, 1);
> if (path_fd < 0) {
> ret = -ENOENT;
> goto out;
> }
> }
> - ret = __ino_to_path_fd(inum, path_fd, full_path);
> + ret = __ino_to_path_fd(inum, path_fd, mount_path);
> if (path_fd != fd)
> close_file_or_dir(path_fd, dirs);
> } else {
> diff --git a/common/utils.c b/common/utils.c
> index 1c264455..1562ac52 100644
> --- a/common/utils.c
> +++ b/common/utils.c
> @@ -1259,9 +1259,6 @@ int find_mount_root(const char *path, const char *data, u8 flag, char **mount_ro
> int longest_matchlen = 0;
> char *longest_match = NULL;
> char *cmp_field = NULL;
> - bool found;
> -
> - BUG_ON(flag != BTRFS_FIND_ROOT_PATH);
>
> fd = open(path, O_RDONLY | O_NOATIME);
> if (fd < 0)
> @@ -1273,12 +1270,32 @@ int find_mount_root(const char *path, const char *data, u8 flag, char **mount_ro
> return -errno;
>
> while ((ent = getmntent(mnttab))) {
> - cmp_field = ent->mnt_dir;
> + bool found = false;
>
> - len = strlen(cmp_field);
> + /* BTRFS_FIND_ROOT_PATH is the default behavior */
> + if (flag == BTRFS_FIND_ROOT_OPTS)
> + cmp_field = ent->mnt_opts;
> + else
> + cmp_field = ent->mnt_dir;
>
> - found = strncmp(cmp_field, data, len) == 0;
> + len = strlen(cmp_field);
>
> + if (flag == BTRFS_FIND_ROOT_OPTS) {
> + size_t dlen = strlen(data);
> + char *tmp_str = strstr(cmp_field, data);
> + /*
> + * Make sure that we are dealing with the wanted string,
> + * since strstr returns the start of the string found.
> + * Compare the end string position from data with the
> + * mount point found, and make sure that we have an
> + * option separator or string end.
> + */
> + if (tmp_str)
> + found = tmp_str[dlen] == ',' ||
> + tmp_str[dlen] == 0;
> + } else {
> + found = strncmp(cmp_field, data, len) == 0;
> + }
> if (found) {
> /* match found and use the latest match */
> if (longest_matchlen <= len) {
> diff --git a/common/utils.h b/common/utils.h
> index 449e1d3e..b5d256c6 100644
> --- a/common/utils.h
> +++ b/common/utils.h
> @@ -54,7 +54,10 @@
>
> enum btrfs_find_root_flags {
> /* check mnt_dir of mntent */
> - BTRFS_FIND_ROOT_PATH = 0
> + BTRFS_FIND_ROOT_PATH = 0,
> +
> + /* check mnt_opts of mntent */
> + BTRFS_FIND_ROOT_OPTS
> };
>
> void units_set_mode(unsigned *units, unsigned mode);
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 0/3] btrfs-progs: Fix logical-resolve
2020-11-27 19:30 [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Marcos Paulo de Souza
` (3 preceding siblings ...)
2020-12-02 20:12 ` [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Josef Bacik
@ 2021-01-14 18:42 ` David Sterba
4 siblings, 0 replies; 7+ messages in thread
From: David Sterba @ 2021-01-14 18:42 UTC (permalink / raw)
To: Marcos Paulo de Souza; +Cc: linux-btrfs, Marcos Paulo de Souza, wqu, dsterba
On Fri, Nov 27, 2020 at 04:30:32PM -0300, Marcos Paulo de Souza wrote:
> From: Marcos Paulo de Souza <mpdesouza@suse.com>
>
> In this forth iteration, only patch 0002 was changed. Previously the variable
> full_path, which is passed by the user, was being overwritten in the inode loop.
> Now we create a temp var to store the mount_point when the lookup is needed.
>
> Please review.
>
> Changes from v3:
> * In patch 0002, do not overwrite full_path variable
For the record, patches have been reworked as there some differences
between kernels 5.3 and 5.8 regarding bind mounts and what is printed in
/proc/ mounts due to 3ef3959b29c4 ("btrfs: don't show full path of bind
mounts in subvol=").
New version uses libmount to parse the information and distinguish
subvol= mounts and bind mounts. With a test.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2021-01-14 18:45 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-11-27 19:30 [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Marcos Paulo de Souza
2020-11-27 19:30 ` [PATCH v4 1/3] btrfs-progs: Adapt find_mount_root to verify other fields of mntent struct Marcos Paulo de Souza
2020-11-27 19:30 ` [PATCH v4 2/3] btrfs-progs: inspect: Fix logical-resolve file path lookup Marcos Paulo de Souza
2020-12-04 0:08 ` Qu Wenruo
2020-11-27 19:30 ` [PATCH v4 3/3] btrfs-progs: tests: Add new logical-resolve test Marcos Paulo de Souza
2020-12-02 20:12 ` [PATCH v4 0/3] btrfs-progs: Fix logical-resolve Josef Bacik
2021-01-14 18:42 ` David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox