diff options
author | Paul Lawrence <paullawrence@google.com> | 2023-08-02 12:23:44 -0700 |
---|---|---|
committer | Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> | 2023-12-20 23:29:34 +0000 |
commit | db0368c50207d934bed3911df74982d4c7fa7805 (patch) | |
tree | 4d139aa1d1ea13c8b929da0949279ecbcf277efc | |
parent | 9dc33a03455f7700da3aee7e52b65af6715d4294 (diff) | |
download | common-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.c | 15 | ||||
-rw-r--r-- | tools/testing/selftests/filesystems/fuse/bpf_loader.c | 28 | ||||
-rw-r--r-- | tools/testing/selftests/filesystems/fuse/fuse_test.c | 45 | ||||
-rw-r--r-- | tools/testing/selftests/filesystems/fuse/test_fuse.h | 3 |
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); |