@@ -245,15 +245,36 @@ static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
path_ptr[-1] = '\0';
path_fd = fd;
} 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;
}
+
+ if (ret < 0)
+ goto out;
+
+ strncpy(full_path, mounted, PATH_MAX);
+ free(mounted);
+
path_fd = btrfs_open_dir(full_path, &dirs, 1);
if (path_fd < 0) {
ret = -ENOENT;
@@ -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) {
@@ -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);