summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Lawrence <paullawrence@google.com>2023-08-02 12:23:44 -0700
committerTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-12-20 23:29:34 +0000
commitdb0368c50207d934bed3911df74982d4c7fa7805 (patch)
tree4d139aa1d1ea13c8b929da0949279ecbcf277efc
parent9dc33a03455f7700da3aee7e52b65af6715d4294 (diff)
downloadcommon-db0368c50207d934bed3911df74982d4c7fa7805.tar.gz
ANDROID: fuse-bpf: Follow mounts in lookups
Bug: 292925770 Test: fuse_test run. The following steps on Android also now pass: Create /data/123 and /data/media/0/Android/data/45 directories Mount /data/123 directory to /data/media/0/Android/data/45 directory Create 1.txt under the /data/123 directory File 1.txt should appear in /storage/emulated/0/Android/data/45 Signed-off-by: Paul Lawrence <paullawrence@google.com> (cherry picked from https://android-review.googlesource.com/q/commit:9323938705b42cb4dd863d5cf8022ba8f2282952) Merged-In: I1fe27d743ca2981e624a9aa87d9ab6deb313aadc Change-Id: I1fe27d743ca2981e624a9aa87d9ab6deb313aadc
-rw-r--r--fs/fuse/backing.c15
-rw-r--r--tools/testing/selftests/filesystems/fuse/bpf_loader.c28
-rw-r--r--tools/testing/selftests/filesystems/fuse/fuse_test.c45
-rw-r--r--tools/testing/selftests/filesystems/fuse/test_fuse.h3
4 files changed, 85 insertions, 6 deletions
diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 3b2b2a470ba4..859114b13508 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -1167,7 +1167,6 @@ int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir,
struct kstat stat;
int err;
- /* TODO this will not handle lookups over mount points */
inode_lock_nested(dir_backing_inode, I_MUTEX_PARENT);
backing_entry = lookup_one_len(entry->d_name.name, dir_backing_entry,
strlen(entry->d_name.name));
@@ -1186,16 +1185,22 @@ int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir,
return 0;
}
+ err = follow_down(&fuse_entry->backing_path);
+ if (err)
+ goto err_out;
+
err = vfs_getattr(&fuse_entry->backing_path, &stat,
STATX_BASIC_STATS, 0);
- if (err) {
- path_put_init(&fuse_entry->backing_path);
- return err;
- }
+ if (err)
+ goto err_out;
fuse_stat_to_attr(get_fuse_conn(dir),
backing_entry->d_inode, &stat, &feo->attr);
return 0;
+
+err_out:
+ path_put_init(&fuse_entry->backing_path);
+ return err;
}
int fuse_handle_backing(struct fuse_entry_bpf *feb, struct inode **backing_inode,
diff --git a/tools/testing/selftests/filesystems/fuse/bpf_loader.c b/tools/testing/selftests/filesystems/fuse/bpf_loader.c
index 933d97bf60ea..b636b18a9eed 100644
--- a/tools/testing/selftests/filesystems/fuse/bpf_loader.c
+++ b/tools/testing/selftests/filesystems/fuse/bpf_loader.c
@@ -394,6 +394,29 @@ int s_rename(struct s oldpathname, struct s newpathname)
return res;
}
+int s_mount(struct s source, struct s target, struct s filesystem,
+ unsigned long mountflags, struct s data)
+{
+ int res;
+
+ res = mount(source.s, target.s, filesystem.s, mountflags, data.s);
+ free(source.s);
+ free(target.s);
+ free(filesystem.s);
+ free(data.s);
+
+ return res;
+}
+
+int s_umount(struct s target)
+{
+ int res;
+
+ res = umount(target.s);
+ free(target.s);
+ return res;
+}
+
int s_fuse_attr(struct s pathname, struct fuse_attr *fuse_attr_out)
{
@@ -574,7 +597,10 @@ static int mount_fuse_maybe_init(const char *mount_dir, int bpf_fd, int dir_fd,
}));
}
- *fuse_dev_ptr = fuse_dev;
+ if (fuse_dev_ptr)
+ *fuse_dev_ptr = fuse_dev;
+ else
+ TESTSYSCALL(close(fuse_dev));
fuse_dev = -1;
result = TEST_SUCCESS;
out:
diff --git a/tools/testing/selftests/filesystems/fuse/fuse_test.c b/tools/testing/selftests/filesystems/fuse/fuse_test.c
index 82db9a4fcbed..c644e80ed4cc 100644
--- a/tools/testing/selftests/filesystems/fuse/fuse_test.c
+++ b/tools/testing/selftests/filesystems/fuse/fuse_test.c
@@ -2127,6 +2127,50 @@ out:
return result;
}
+/**
+ * Test that fuse passthrough correctly traverses a mount point on the lower fs
+ */
+static int bpf_test_follow_mounts(const char *mount_dir)
+{
+ const char *bind_src = "bind_src";
+ const char *bind_dst = "bind_dst";
+ const char *file = "file";
+ int fd = -1;
+ int src_fd = -1;
+ int result = TEST_FAILURE;
+
+ TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(bind_src)), 0777));
+ TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(bind_dst)), 0777));
+ TEST(fd = s_creat(s_pathn(3, s(ft_src), s(bind_src), s(file)), 0777),
+ fd != -1);
+ TESTSYSCALL(close(fd));
+ fd = -1;
+ TESTSYSCALL(s_mount(s_path(s(ft_src), s(bind_src)),
+ s_path(s(ft_src), s(bind_dst)),
+ s(NULL), MS_BIND, s(NULL)));
+ TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
+ src_fd != -1);
+ TESTEQUAL(mount_fuse_no_init(mount_dir, -1, src_fd, NULL), 0);
+ TEST(fd = s_open(s_pathn(3, s(mount_dir), s(bind_src), s(file)),
+ O_RDONLY),
+ fd != -1);
+ TESTSYSCALL(close(fd));
+ fd = -1;
+ TEST(fd = s_open(s_pathn(3, s(mount_dir), s(bind_dst), s(file)),
+ O_RDONLY),
+ fd != -1);
+ TESTSYSCALL(close(fd));
+ fd = -1;
+
+ result = TEST_SUCCESS;
+out:
+ umount(mount_dir);
+ close(src_fd);
+ s_umount(s_path(s(ft_src), s(bind_dst)));
+ close(fd);
+ return result;
+}
+
static void parse_range(const char *ranges, bool *run_test, size_t tests)
{
size_t i;
@@ -2257,6 +2301,7 @@ int main(int argc, char *argv[])
MAKE_TEST(bpf_test_create_and_remove_bpf),
MAKE_TEST(bpf_test_mkdir_and_remove_bpf),
MAKE_TEST(bpf_test_readahead),
+ MAKE_TEST(bpf_test_follow_mounts),
};
#undef MAKE_TEST
diff --git a/tools/testing/selftests/filesystems/fuse/test_fuse.h b/tools/testing/selftests/filesystems/fuse/test_fuse.h
index 09d1b884f29b..552b0c3e512d 100644
--- a/tools/testing/selftests/filesystems/fuse/test_fuse.h
+++ b/tools/testing/selftests/filesystems/fuse/test_fuse.h
@@ -63,6 +63,9 @@ int s_setxattr(struct s pathname, const char name[], const void *value,
size_t size, int flags);
int s_removexattr(struct s pathname, const char name[]);
int s_rename(struct s oldpathname, struct s newpathname);
+int s_mount(struct s source, struct s target, struct s filesystem,
+ unsigned long mountflags, struct s data);
+int s_umount(struct s target);
struct s tracing_folder(void);
int tracing_on(void);