mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
ANDROID: fuse: Don't use readdirplus w/ nodeid 0
If we have a nodeid of 0, we've probably got a backing inode, and a regular getattr will be fast. Otherwise, userspace is likely ill suited to properly handle a readdirplus anyways. Test: fuse_test Bug: 219958836 Signed-off-by: Daniel Rosenberg <drosen@google.com> Change-Id: I02f031d87dcc5fcbe1e080e4f8ec92187b00fe2d
This commit is contained in:
@@ -20,6 +20,8 @@ static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)
|
|||||||
|
|
||||||
if (!fc->do_readdirplus)
|
if (!fc->do_readdirplus)
|
||||||
return false;
|
return false;
|
||||||
|
if (fi->nodeid == 0)
|
||||||
|
return false;
|
||||||
if (!fc->readdirplus_auto)
|
if (!fc->readdirplus_auto)
|
||||||
return true;
|
return true;
|
||||||
if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
|
if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
|
||||||
|
|||||||
@@ -1677,6 +1677,107 @@ out:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bpf_test_no_readdirplus_without_nodeid(const char *mount_dir)
|
||||||
|
{
|
||||||
|
const char *folder1 = "folder1";
|
||||||
|
const char *folder2 = "folder2";
|
||||||
|
int result = TEST_FAILURE;
|
||||||
|
int fuse_dev = -1;
|
||||||
|
int src_fd = -1;
|
||||||
|
int content_fd = -1;
|
||||||
|
int bpf_fd = -1;
|
||||||
|
int pid = -1;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_readdirplus",
|
||||||
|
&bpf_fd, NULL, NULL), 0);
|
||||||
|
TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
|
||||||
|
TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder2)), 0777));
|
||||||
|
TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
|
||||||
|
FUSE_ACTION
|
||||||
|
DIR *open_dir = NULL;
|
||||||
|
struct dirent *dirent;
|
||||||
|
|
||||||
|
// Folder 1: Readdir with no nodeid
|
||||||
|
TEST(open_dir = s_opendir(s_path(s(ft_dst), s(folder1))),
|
||||||
|
open_dir != NULL);
|
||||||
|
TEST(dirent = readdir(open_dir), dirent == NULL);
|
||||||
|
TESTCOND(errno == EINVAL);
|
||||||
|
TESTSYSCALL(closedir(open_dir));
|
||||||
|
open_dir = NULL;
|
||||||
|
|
||||||
|
// Folder 2: Readdir with a nodeid
|
||||||
|
TEST(open_dir = s_opendir(s_path(s(ft_dst), s(folder2))),
|
||||||
|
open_dir != NULL);
|
||||||
|
TEST(dirent = readdir(open_dir), dirent == NULL);
|
||||||
|
TESTCOND(errno == EINVAL);
|
||||||
|
TESTSYSCALL(closedir(open_dir));
|
||||||
|
open_dir = NULL;
|
||||||
|
FUSE_DAEMON
|
||||||
|
size_t read_size;
|
||||||
|
struct fuse_in_header *in_header = (struct fuse_in_header *)bytes_in;
|
||||||
|
struct fuse_attr attr = {};
|
||||||
|
int backing_fd = -1;
|
||||||
|
|
||||||
|
TESTFUSEINITFLAGS(FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO);
|
||||||
|
|
||||||
|
// folder 1: Set 0 as nodeid, Expect READDIR
|
||||||
|
TESTFUSELOOKUP(folder1, 0);
|
||||||
|
TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
|
||||||
|
O_DIRECTORY | O_RDONLY | O_CLOEXEC),
|
||||||
|
backing_fd != -1);
|
||||||
|
TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
|
||||||
|
.nodeid = 0,
|
||||||
|
.generation = 0,
|
||||||
|
.entry_valid = UINT64_MAX,
|
||||||
|
.attr_valid = UINT64_MAX,
|
||||||
|
.entry_valid_nsec = UINT32_MAX,
|
||||||
|
.attr_valid_nsec = UINT32_MAX,
|
||||||
|
.attr = attr,
|
||||||
|
}), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
|
||||||
|
.backing_action = FUSE_ACTION_REPLACE,
|
||||||
|
.backing_fd = backing_fd,
|
||||||
|
.bpf_action = FUSE_ACTION_REPLACE,
|
||||||
|
.bpf_fd = bpf_fd,
|
||||||
|
}));
|
||||||
|
TESTSYSCALL(close(backing_fd));
|
||||||
|
TEST(read_size = read(fuse_dev, bytes_in, sizeof(bytes_in)), read_size > 0);
|
||||||
|
TESTEQUAL(in_header->opcode, FUSE_READDIR);
|
||||||
|
TESTFUSEOUTERROR(-EINVAL);
|
||||||
|
|
||||||
|
// folder 2: Set 10 as nodeid, Expect READDIRPLUS
|
||||||
|
TESTFUSELOOKUP(folder2, 0);
|
||||||
|
TEST(backing_fd = s_open(s_path(s(ft_src), s(folder2)),
|
||||||
|
O_DIRECTORY | O_RDONLY | O_CLOEXEC),
|
||||||
|
backing_fd != -1);
|
||||||
|
TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
|
||||||
|
.nodeid = 10,
|
||||||
|
.generation = 0,
|
||||||
|
.entry_valid = UINT64_MAX,
|
||||||
|
.attr_valid = UINT64_MAX,
|
||||||
|
.entry_valid_nsec = UINT32_MAX,
|
||||||
|
.attr_valid_nsec = UINT32_MAX,
|
||||||
|
.attr = attr,
|
||||||
|
}), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
|
||||||
|
.backing_action = FUSE_ACTION_REPLACE,
|
||||||
|
.backing_fd = backing_fd,
|
||||||
|
.bpf_action = FUSE_ACTION_REPLACE,
|
||||||
|
.bpf_fd = bpf_fd,
|
||||||
|
}));
|
||||||
|
TESTSYSCALL(close(backing_fd));
|
||||||
|
TEST(read_size = read(fuse_dev, bytes_in, sizeof(bytes_in)), read_size > 0);
|
||||||
|
TESTEQUAL(in_header->opcode, FUSE_READDIRPLUS);
|
||||||
|
TESTFUSEOUTERROR(-EINVAL);
|
||||||
|
FUSE_DONE
|
||||||
|
result = TEST_SUCCESS;
|
||||||
|
out:
|
||||||
|
close(fuse_dev);
|
||||||
|
close(content_fd);
|
||||||
|
close(src_fd);
|
||||||
|
close(bpf_fd);
|
||||||
|
umount(mount_dir);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_options(int argc, char *const *argv)
|
static int parse_options(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
@@ -1782,7 +1883,8 @@ int main(int argc, char *argv[])
|
|||||||
MAKE_TEST(inotify_test),
|
MAKE_TEST(inotify_test),
|
||||||
MAKE_TEST(bpf_test_statfs),
|
MAKE_TEST(bpf_test_statfs),
|
||||||
MAKE_TEST(bpf_test_lseek),
|
MAKE_TEST(bpf_test_lseek),
|
||||||
MAKE_TEST(bpf_test_readdirplus_not_overriding_backing)
|
MAKE_TEST(bpf_test_readdirplus_not_overriding_backing),
|
||||||
|
MAKE_TEST(bpf_test_no_readdirplus_without_nodeid)
|
||||||
};
|
};
|
||||||
#undef MAKE_TEST
|
#undef MAKE_TEST
|
||||||
|
|
||||||
|
|||||||
@@ -514,3 +514,13 @@ int error_test(struct fuse_bpf_args *fa)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SEC("test_readdirplus")
|
||||||
|
int readdirplus_test(struct fuse_bpf_args *fa)
|
||||||
|
{
|
||||||
|
switch (fa->opcode) {
|
||||||
|
case FUSE_READDIR | FUSE_PREFILTER: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FUSE_BPF_BACKING;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user