mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 12:00:22 +09:00
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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user