mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
ANDROID: fuse-bpf: Support FUSE_STATFS
Adds support for FUSE_STATFS, needed to run various filesystem tests Bug: 217570523 Test: bpf_test_statfs Change-Id: I5ee13e880118c5c79c4ca17bb2e902a3e17a7eb8 Signed-off-by: Daniel Rosenberg <drosen@google.com>
This commit is contained in:
@@ -1786,6 +1786,56 @@ void *fuse_setattr_finalize(struct fuse_args *fa,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fuse_statfs_initialize(
|
||||
struct fuse_args *fa, struct fuse_statfs_out *fso,
|
||||
struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
*fso = (struct fuse_statfs_out) {0};
|
||||
*fa = (struct fuse_args) {
|
||||
.nodeid = get_node_id(d_inode(dentry)),
|
||||
.opcode = FUSE_STATFS,
|
||||
.out_numargs = 1,
|
||||
.out_numargs = 1,
|
||||
.out_args[0].size = sizeof(fso),
|
||||
.out_args[0].value = fso,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_statfs_backing(
|
||||
struct fuse_args *fa,
|
||||
struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
int err = 0;
|
||||
struct path backing_path;
|
||||
struct fuse_statfs_out *fso = fa->out_args[0].value;
|
||||
|
||||
get_fuse_backing_path(dentry, &backing_path);
|
||||
if (!backing_path.dentry)
|
||||
return -EBADF;
|
||||
err = vfs_statfs(&backing_path, buf);
|
||||
path_put(&backing_path);
|
||||
buf->f_type = FUSE_SUPER_MAGIC;
|
||||
|
||||
//TODO Provide postfilter opportunity to modify
|
||||
if (!err)
|
||||
convert_statfs_to_fuse(&fso->st, buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void *fuse_statfs_finalize(
|
||||
struct fuse_args *fa,
|
||||
struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
struct fuse_statfs_out *fso = fa->out_args[0].value;
|
||||
|
||||
if (!fa->error_in)
|
||||
convert_fuse_statfs(buf, &fso->st);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *unused,
|
||||
struct inode *inode, struct dentry *dentry,
|
||||
struct delayed_call *callback, const char **out)
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include <linux/pid_namespace.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include <linux/statfs.h>
|
||||
|
||||
#define FUSE_SUPER_MAGIC 0x65735546
|
||||
|
||||
/** Default max number of pages that can be used in a single read request */
|
||||
#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
|
||||
@@ -1567,6 +1570,13 @@ int fuse_setattr_backing(struct fuse_args *fa,
|
||||
void *fuse_setattr_finalize(struct fuse_args *fa,
|
||||
struct dentry *dentry, struct iattr *attr, struct file *file);
|
||||
|
||||
int fuse_statfs_initialize(struct fuse_args *fa, struct fuse_statfs_out *fso,
|
||||
struct dentry *dentry, struct kstatfs *buf);
|
||||
int fuse_statfs_backing(struct fuse_args *fa,
|
||||
struct dentry *dentry, struct kstatfs *buf);
|
||||
void *fuse_statfs_finalize(struct fuse_args *fa,
|
||||
struct dentry *dentry, struct kstatfs *buf);
|
||||
|
||||
int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *dummy,
|
||||
struct inode *inode, struct dentry *dentry,
|
||||
struct delayed_call *callback, const char **out);
|
||||
@@ -1708,6 +1718,33 @@ static inline int finalize_attr(struct inode *inode, struct fuse_attr_out *outar
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void convert_statfs_to_fuse(struct fuse_kstatfs *attr, struct kstatfs *stbuf)
|
||||
{
|
||||
attr->bsize = stbuf->f_bsize;
|
||||
attr->frsize = stbuf->f_frsize;
|
||||
attr->blocks = stbuf->f_blocks;
|
||||
attr->bfree = stbuf->f_bfree;
|
||||
attr->bavail = stbuf->f_bavail;
|
||||
attr->files = stbuf->f_files;
|
||||
attr->ffree = stbuf->f_ffree;
|
||||
attr->namelen = stbuf->f_namelen;
|
||||
/* fsid is left zero */
|
||||
}
|
||||
|
||||
static inline void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
|
||||
{
|
||||
stbuf->f_type = FUSE_SUPER_MAGIC;
|
||||
stbuf->f_bsize = attr->bsize;
|
||||
stbuf->f_frsize = attr->frsize;
|
||||
stbuf->f_blocks = attr->blocks;
|
||||
stbuf->f_bfree = attr->bfree;
|
||||
stbuf->f_bavail = attr->bavail;
|
||||
stbuf->f_files = attr->files;
|
||||
stbuf->f_ffree = attr->ffree;
|
||||
stbuf->f_namelen = attr->namelen;
|
||||
/* fsid is left zero */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FUSE_BPF
|
||||
struct fuse_err_ret {
|
||||
void *result;
|
||||
|
||||
@@ -50,8 +50,6 @@ MODULE_PARM_DESC(max_user_congthresh,
|
||||
"Global limit for the maximum congestion threshold an "
|
||||
"unprivileged user can set");
|
||||
|
||||
#define FUSE_SUPER_MAGIC 0x65735546
|
||||
|
||||
#define FUSE_DEFAULT_BLKSIZE 512
|
||||
|
||||
/** Maximum number of outstanding background requests */
|
||||
@@ -549,20 +547,6 @@ static void fuse_put_super(struct super_block *sb)
|
||||
fuse_mount_put(fm);
|
||||
}
|
||||
|
||||
static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
|
||||
{
|
||||
stbuf->f_type = FUSE_SUPER_MAGIC;
|
||||
stbuf->f_bsize = attr->bsize;
|
||||
stbuf->f_frsize = attr->frsize;
|
||||
stbuf->f_blocks = attr->blocks;
|
||||
stbuf->f_bfree = attr->bfree;
|
||||
stbuf->f_bavail = attr->bavail;
|
||||
stbuf->f_files = attr->files;
|
||||
stbuf->f_ffree = attr->ffree;
|
||||
stbuf->f_namelen = attr->namelen;
|
||||
/* fsid is left zero */
|
||||
}
|
||||
|
||||
static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
struct super_block *sb = dentry->d_sb;
|
||||
@@ -570,12 +554,24 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
FUSE_ARGS(args);
|
||||
struct fuse_statfs_out outarg;
|
||||
int err;
|
||||
#ifdef CONFIG_FUSE_BPF
|
||||
struct fuse_err_ret fer;
|
||||
#endif
|
||||
|
||||
if (!fuse_allow_current_process(fm->fc)) {
|
||||
buf->f_type = FUSE_SUPER_MAGIC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FUSE_BPF
|
||||
fer = fuse_bpf_backing(dentry->d_inode, struct fuse_statfs_out,
|
||||
fuse_statfs_initialize, fuse_statfs_backing,
|
||||
fuse_statfs_finalize,
|
||||
dentry, buf);
|
||||
if (fer.ret)
|
||||
return PTR_ERR(fer.result);
|
||||
#endif
|
||||
|
||||
memset(&outarg, 0, sizeof(outarg));
|
||||
args.in_numargs = 0;
|
||||
args.opcode = FUSE_STATFS;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
#include <linux/unistd.h>
|
||||
@@ -302,6 +303,20 @@ int s_stat(struct s pathname, struct stat *st)
|
||||
return res;
|
||||
}
|
||||
|
||||
int s_statfs(struct s pathname, struct statfs *st)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!pathname.s) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = statfs(pathname.s, st);
|
||||
free(pathname.s);
|
||||
return res;
|
||||
}
|
||||
|
||||
DIR *s_opendir(struct s pathname)
|
||||
{
|
||||
DIR *res;
|
||||
|
||||
@@ -284,6 +284,11 @@ int trace_daemon(struct fuse_args *fa)
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
case FUSE_STATFS | FUSE_PREFILTER: {
|
||||
bpf_printk("statfs %d", fa->nodeid);
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
default:
|
||||
if (fa->opcode & FUSE_PREFILTER)
|
||||
bpf_printk("prefilter *** UNKNOWN *** opcode: %d",
|
||||
|
||||
@@ -1422,6 +1422,34 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int bpf_test_statfs(const char *mount_dir)
|
||||
{
|
||||
int result = TEST_FAILURE;
|
||||
int src_fd = -1;
|
||||
int bpf_fd = -1;
|
||||
int fuse_dev = -1;
|
||||
int fd = -1;
|
||||
struct statfs st;
|
||||
|
||||
TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
|
||||
src_fd != -1);
|
||||
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
|
||||
&bpf_fd, NULL, NULL), 0);
|
||||
TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
|
||||
|
||||
TESTSYSCALL(s_statfs(s(mount_dir), &st));
|
||||
TESTEQUAL(bpf_test_trace("statfs"), 0);
|
||||
TESTEQUAL(st.f_type, 0x65735546);
|
||||
result = TEST_SUCCESS;
|
||||
out:
|
||||
close(fd);
|
||||
umount(mount_dir);
|
||||
close(fuse_dev);
|
||||
close(bpf_fd);
|
||||
close(src_fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int parse_options(int argc, char *const *argv)
|
||||
{
|
||||
signed char c;
|
||||
@@ -1524,6 +1552,7 @@ int main(int argc, char *argv[])
|
||||
MAKE_TEST(mmap_test),
|
||||
MAKE_TEST(readdir_perms_test),
|
||||
MAKE_TEST(inotify_test),
|
||||
MAKE_TEST(bpf_test_statfs),
|
||||
};
|
||||
#undef MAKE_TEST
|
||||
|
||||
|
||||
@@ -341,6 +341,11 @@ int trace_test(struct fuse_args *fa)
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
case FUSE_STATFS | FUSE_PREFILTER: {
|
||||
bpf_printk("statfs");
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
default:
|
||||
bpf_printk("Unknown opcode %d", fa->opcode);
|
||||
return 0;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
@@ -50,6 +51,7 @@ int s_openat(int dirfd, struct s pathname, int flags, ...);
|
||||
int s_creat(struct s pathname, mode_t mode);
|
||||
int s_mkfifo(struct s pathname, mode_t mode);
|
||||
int s_stat(struct s pathname, struct stat *st);
|
||||
int s_statfs(struct s pathname, struct statfs *st);
|
||||
DIR *s_opendir(struct s pathname);
|
||||
int s_getxattr(struct s pathname, const char name[], void *value, size_t size,
|
||||
ssize_t *ret_size);
|
||||
|
||||
Reference in New Issue
Block a user