UPSTREAM: 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:
Daniel Rosenberg 2022-02-02 17:36:24 -08:00 • committed by Alexander Martinz
commit a454ffc049
No known key found for this signature in database
GPG key ID: CF15BDD9A321A9B2
3 changed files with 99 additions and 16 deletions

View file

@ -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)

View file

@ -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
@ -1565,6 +1568,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);
@ -1706,6 +1716,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;

View file

@ -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 */
@ -554,20 +552,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;
@ -575,12 +559,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;