ANDROID: fuse-bpf: Make inodes with backing_fd reachable

for regular FUSE fuse_iget

Currently, when we’re trying to find inode based on their
backing inode we strictly checking on nodeid == 0, so
basically we’re not supporting nodeid != 0 for inode,
which is backed by another one. Alongside with this, we’re
using backing_inode as a hash for inode which make this inode
not reachable for regular FUSE fuse_iget that as a result
causing backing_inode losing because instead of getting
existent one (with backing inode) we create a new one as
a part of readdirplus.

For more details please check: go/fuse-loosing-inode-with-backing

Bug: 219958836
Test: Manually checked that /data and /obb inodes
always have inode numbers configured.
Co-developed-by: Paul Lawrence <paullawrence@google.com>

Change-Id: If6a5fb340561ac6320d3c4e86215f1bcd4c2c10c
Signed-off-by: Dmitrii Merkurev <dimorinny@google.com>
This commit is contained in:
Dmitrii Merkurev
2022-06-29 22:17:20 +00:00
parent 6210ced850
commit 4ad093cae1
4 changed files with 55 additions and 15 deletions

View File

@@ -262,6 +262,8 @@ int fuse_create_open_backing(
struct dentry *newent;
int err = 0;
const struct fuse_create_in *fci = fa->in_args[0].value;
struct fuse_inode *fuse_inode = get_fuse_inode(entry->d_inode);
u64 target_nodeid = 0;
if (!dir_fuse_inode || !dir_fuse_dentry)
return -EIO;
@@ -293,7 +295,10 @@ int fuse_create_open_backing(
};
path_get(&get_fuse_dentry(entry)->backing_path);
inode = fuse_iget_backing(dir->i_sb,
if (fuse_inode)
target_nodeid = fuse_inode->nodeid;
inode = fuse_iget_backing(dir->i_sb, target_nodeid,
get_fuse_dentry(entry)->backing_path.dentry->d_inode);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
@@ -1173,9 +1178,11 @@ struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir,
struct fuse_dentry *fd;
struct dentry *bd;
struct inode *inode, *backing_inode;
struct fuse_inode *fuse_inode = get_fuse_inode(entry->d_inode);
struct fuse_entry_out *feo = fa->out_args[0].value;
struct fuse_entry_bpf_out *febo = fa->out_args[1].value;
struct fuse_entry_bpf *feb = container_of(febo, struct fuse_entry_bpf, out);
u64 target_nodeid = 0;
fd = get_fuse_dentry(entry);
if (!fd)
@@ -1187,7 +1194,10 @@ struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir,
if (!backing_inode)
return 0;
inode = fuse_iget_backing(dir->i_sb, backing_inode);
if (fuse_inode)
target_nodeid = fuse_inode->nodeid;
inode = fuse_iget_backing(dir->i_sb, target_nodeid, backing_inode);
if (IS_ERR(inode))
return ERR_PTR(PTR_ERR(inode));
@@ -1349,7 +1359,8 @@ int fuse_mknod_backing(
{
int err = 0;
const struct fuse_mknod_in *fmi = fa->in_args[0].value;
struct inode *backing_inode = get_fuse_inode(dir)->backing_inode;
struct fuse_inode *fuse_inode = get_fuse_inode(dir);
struct inode *backing_inode = fuse_inode->backing_inode;
struct path backing_path = {};
struct inode *inode = NULL;
@@ -1376,7 +1387,7 @@ int fuse_mknod_backing(
*/
goto out;
}
inode = fuse_iget_backing(dir->i_sb, backing_inode);
inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto out;
@@ -1425,7 +1436,8 @@ int fuse_mkdir_backing(
{
int err = 0;
const struct fuse_mkdir_in *fmi = fa->in_args[0].value;
struct inode *backing_inode = get_fuse_inode(dir)->backing_inode;
struct fuse_inode *fuse_inode = get_fuse_inode(dir);
struct inode *backing_inode = fuse_inode->backing_inode;
struct path backing_path = {};
struct inode *inode = NULL;
struct dentry *d;
@@ -1453,7 +1465,7 @@ int fuse_mkdir_backing(
dput(backing_path.dentry);
backing_path.dentry = d;
}
inode = fuse_iget_backing(dir->i_sb, backing_inode);
inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto out;
@@ -1768,7 +1780,8 @@ int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry,
struct path backing_new_path = {};
struct dentry *backing_dir_dentry;
struct inode *fuse_new_inode = NULL;
struct inode *backing_dir_inode = get_fuse_inode(dir)->backing_inode;
struct fuse_inode *fuse_dir_inode = get_fuse_inode(dir);
struct inode *backing_dir_inode = fuse_dir_inode->backing_inode;
get_fuse_backing_path(entry, &backing_old_path);
if (!backing_old_path.dentry)
@@ -1799,7 +1812,7 @@ int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry,
goto out;
}
fuse_new_inode = fuse_iget_backing(dir->i_sb, backing_dir_inode);
fuse_new_inode = fuse_iget_backing(dir->i_sb, fuse_dir_inode->nodeid, backing_dir_inode);
if (IS_ERR(fuse_new_inode)) {
err = PTR_ERR(fuse_new_inode);
goto out;
@@ -2163,7 +2176,8 @@ int fuse_symlink_backing(
struct inode *dir, struct dentry *entry, const char *link, int len)
{
int err = 0;
struct inode *backing_inode = get_fuse_inode(dir)->backing_inode;
struct fuse_inode *fuse_inode = get_fuse_inode(dir);
struct inode *backing_inode = fuse_inode->backing_inode;
struct path backing_path = {};
struct inode *inode = NULL;
@@ -2186,7 +2200,7 @@ int fuse_symlink_backing(
*/
goto out;
}
inode = fuse_iget_backing(dir->i_sb, backing_inode);
inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto out;

View File

@@ -545,7 +545,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
goto out_queue_forget;
backing_inode = backing_file->f_inode;
*inode = fuse_iget_backing(sb, backing_inode);
*inode = fuse_iget_backing(sb, outarg->nodeid, backing_inode);
if (!*inode)
goto bpf_arg_out;

View File

@@ -976,9 +976,10 @@ extern const struct dentry_operations fuse_dentry_operations;
extern const struct dentry_operations fuse_root_dentry_operations;
/**
* Get a filled in inode
* Get a filled-in inode
*/
struct inode *fuse_iget_backing(struct super_block *sb,
u64 nodeid,
struct inode *backing_inode);
struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
int generation, struct fuse_attr *attr,

View File

@@ -330,6 +330,15 @@ static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
(struct fuse_inode_identifier *) _nodeidp;
struct fuse_inode *fi = get_fuse_inode(inode);
return fii->nodeid == fi->nodeid;
}
static int fuse_inode_backing_eq(struct inode *inode, void *_nodeidp)
{
struct fuse_inode_identifier *fii =
(struct fuse_inode_identifier *) _nodeidp;
struct fuse_inode *fi = get_fuse_inode(inode);
return fii->nodeid == fi->nodeid
#ifdef CONFIG_FUSE_BPF
&& fii->backing_inode == fi->backing_inode
@@ -344,6 +353,17 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp)
struct fuse_inode *fi = get_fuse_inode(inode);
fi->nodeid = fii->nodeid;
return 0;
}
static int fuse_inode_backing_set(struct inode *inode, void *_nodeidp)
{
struct fuse_inode_identifier *fii =
(struct fuse_inode_identifier *) _nodeidp;
struct fuse_inode *fi = get_fuse_inode(inode);
fi->nodeid = fii->nodeid;
#ifdef CONFIG_FUSE_BPF
fi->backing_inode = fii->backing_inode;
if (fi->backing_inode)
@@ -353,20 +373,25 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp)
return 0;
}
struct inode *fuse_iget_backing(struct super_block *sb,
struct inode *fuse_iget_backing(struct super_block *sb, u64 nodeid,
struct inode *backing_inode)
{
struct inode *inode;
struct fuse_inode *fi;
struct fuse_conn *fc = get_fuse_conn_super(sb);
struct fuse_inode_identifier fii = {
.nodeid = nodeid,
.backing_inode = backing_inode,
};
struct fuse_attr attr;
unsigned long hash = (unsigned long) backing_inode;
if (nodeid)
hash = nodeid;
fuse_fill_attr_from_inode(&attr, backing_inode);
inode = iget5_locked(sb, (unsigned long) backing_inode, fuse_inode_eq,
fuse_inode_set, &fii);
inode = iget5_locked(sb, hash, fuse_inode_backing_eq,
fuse_inode_backing_set, &fii);
if (!inode)
return NULL;