summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-08-02 03:00:29 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-08-02 03:00:29 +0000
commit0abbe299f08448856ba8cde44e9124dcc3a7a0e4 (patch)
treecd87675190dc011a7714d5b0a9b1e93ecd498eaa
parentf4141658b798dd4deac913a02ee9bcfd0c1ba3f9 (diff)
parent5c7ff5dc7aace613470615ca3453d37c407a3551 (diff)
downloadcommon-android-gs-bluejay-5.10-u-beta5.tar.gz
Change-Id: Ibcc2b9edd46f82307af8c5eba41a6897a614168a
-rw-r--r--fs/f2fs/f2fs.h1
-rw-r--r--fs/f2fs/super.c1
-rw-r--r--fs/f2fs/xattr.c31
-rw-r--r--fs/fuse/backing.c81
-rw-r--r--fs/fuse/dev.c2
-rw-r--r--fs/fuse/dir.c33
-rw-r--r--fs/fuse/fuse_i.h14
-rw-r--r--fs/fuse/inode.c23
-rw-r--r--fs/notify/inotify/inotify_user.c8
-rw-r--r--include/linux/fsnotify.h5
10 files changed, 120 insertions, 79 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index d9e038d42548..91458b9dcb2b 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -808,7 +808,6 @@ struct f2fs_inode_info {
/* avoid racing between foreground op and gc */
struct f2fs_rwsem i_gc_rwsem[2];
struct f2fs_rwsem i_mmap_sem;
- struct f2fs_rwsem i_xattr_sem; /* avoid racing between reading and changing EAs */
int i_extra_isize; /* size of extra space located in i_addr */
kprojid_t i_projid; /* id for project quota */
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 0d20b52ae247..eb34fed89b8f 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1390,7 +1390,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
init_f2fs_rwsem(&fi->i_gc_rwsem[READ]);
init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]);
init_f2fs_rwsem(&fi->i_mmap_sem);
- init_f2fs_rwsem(&fi->i_xattr_sem);
/* Will be used by directory only */
fi->i_dir_level = F2FS_SB(sb)->dir_level;
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 8d1c8efb643c..5b48357a7e91 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -428,7 +428,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
size_t inline_size = inline_xattr_size(inode);
- struct page *in_page = NULL;
+ struct page *in_page = ipage;
void *xattr_addr;
void *inline_addr = NULL;
struct page *xpage;
@@ -441,29 +441,19 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
/* write to inline xattr */
if (inline_size) {
- if (ipage) {
- inline_addr = inline_xattr_addr(inode, ipage);
- } else {
+ if (!in_page) {
in_page = f2fs_get_node_page(sbi, inode->i_ino);
if (IS_ERR(in_page)) {
f2fs_alloc_nid_failed(sbi, new_nid);
return PTR_ERR(in_page);
}
- inline_addr = inline_xattr_addr(inode, in_page);
}
+ inline_addr = inline_xattr_addr(inode, in_page);
- f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
- NODE, true, true);
- /* no need to use xattr node block */
+ f2fs_wait_on_page_writeback(in_page, NODE, true, true);
if (hsize <= inline_size) {
- err = f2fs_truncate_xattr_node(inode);
- f2fs_alloc_nid_failed(sbi, new_nid);
- if (err) {
- f2fs_put_page(in_page, 1);
- return err;
- }
memcpy(inline_addr, txattr_addr, inline_size);
- set_page_dirty(ipage ? ipage : in_page);
+ set_page_dirty(in_page);
goto in_page_out;
}
}
@@ -497,12 +487,13 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
if (inline_size)
- set_page_dirty(ipage ? ipage : in_page);
+ set_page_dirty(in_page);
set_page_dirty(xpage);
f2fs_put_page(xpage, 1);
in_page_out:
- f2fs_put_page(in_page, 1);
+ if (in_page != ipage)
+ f2fs_put_page(in_page, 1);
return err;
}
@@ -523,10 +514,8 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
if (len > F2FS_NAME_LEN)
return -ERANGE;
- f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
error = lookup_all_xattrs(inode, ipage, index, len, name,
&entry, &base_addr, &base_size, &is_inline);
- f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
if (error)
return error;
@@ -560,9 +549,7 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
int error;
size_t rest = buffer_size;
- f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
error = read_all_xattrs(inode, NULL, &base_addr);
- f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
if (error)
return error;
@@ -784,9 +771,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
- f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
- f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
f2fs_unlock_op(sbi);
f2fs_update_time(sbi, REQ_TIME);
diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 8ab36055c967..19e690aaffb1 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -1222,8 +1222,6 @@ int fuse_handle_backing(struct fuse_entry_bpf *feb, struct inode **backing_inode
path_put(backing_path);
*backing_path = backing_file->f_path;
path_get(backing_path);
-
- fput(backing_file);
break;
}
@@ -1237,39 +1235,36 @@ int fuse_handle_backing(struct fuse_entry_bpf *feb, struct inode **backing_inode
int fuse_handle_bpf_prog(struct fuse_entry_bpf *feb, struct inode *parent,
struct bpf_prog **bpf)
{
- struct bpf_prog *new_bpf;
-
- /* Parent isn't presented, but we want to keep
- * Don't touch bpf program at all in this case
- */
- if (feb->out.bpf_action == FUSE_ACTION_KEEP && !parent)
- return 0;
+ struct bpf_prog *new_bpf = NULL;
switch (feb->out.bpf_action) {
case FUSE_ACTION_KEEP: {
- struct fuse_inode *pi = get_fuse_inode(parent);
+ /* Parent isn't presented, but we want to keep
+ * Don't touch bpf program at all in this case
+ */
+ if (!parent)
+ return 0;
- new_bpf = pi->bpf;
+ new_bpf = get_fuse_inode(parent)->bpf;
if (new_bpf)
bpf_prog_inc(new_bpf);
break;
}
case FUSE_ACTION_REMOVE:
- new_bpf = NULL;
break;
case FUSE_ACTION_REPLACE: {
struct file *bpf_file = feb->bpf_file;
- struct bpf_prog *bpf_prog = ERR_PTR(-EINVAL);
- if (bpf_file && !IS_ERR(bpf_file))
- bpf_prog = fuse_get_bpf_prog(bpf_file);
-
- if (IS_ERR(bpf_prog))
- return PTR_ERR(bpf_prog);
+ if (!bpf_file)
+ return -EINVAL;
+ if (IS_ERR(bpf_file))
+ return PTR_ERR(bpf_file);
- new_bpf = bpf_prog;
+ new_bpf = fuse_get_bpf_prog(bpf_file);
+ if (IS_ERR(new_bpf))
+ return PTR_ERR(new_bpf);
break;
}
@@ -1279,7 +1274,8 @@ int fuse_handle_bpf_prog(struct fuse_entry_bpf *feb, struct inode *parent,
/* Cannot change existing program */
if (*bpf) {
- bpf_prog_put(new_bpf);
+ if (new_bpf)
+ bpf_prog_put(new_bpf);
return new_bpf == *bpf ? 0 : -EINVAL;
}
@@ -1299,36 +1295,55 @@ struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir,
struct fuse_entry_bpf *feb = container_of(febo, struct fuse_entry_bpf, out);
int error = -1;
u64 target_nodeid = 0;
+ struct dentry *ret;
fd = get_fuse_dentry(entry);
- if (!fd)
- return ERR_PTR(-EIO);
+ if (!fd) {
+ ret = ERR_PTR(-EIO);
+ goto out;
+ }
+
bd = fd->backing_path.dentry;
- if (!bd)
- return ERR_PTR(-ENOENT);
+ if (!bd) {
+ ret = ERR_PTR(-ENOENT);
+ goto out;
+ }
+
backing_inode = bd->d_inode;
- if (!backing_inode)
- return 0;
+ if (!backing_inode) {
+ ret = 0;
+ goto out;
+ }
if (d_inode)
target_nodeid = get_fuse_inode(d_inode)->nodeid;
inode = fuse_iget_backing(dir->i_sb, target_nodeid, backing_inode);
- if (IS_ERR(inode))
- return ERR_PTR(PTR_ERR(inode));
+ if (IS_ERR(inode)) {
+ ret = ERR_PTR(PTR_ERR(inode));
+ goto out;
+ }
error = fuse_handle_bpf_prog(feb, dir, &get_fuse_inode(inode)->bpf);
- if (error)
- return ERR_PTR(error);
+ if (error) {
+ ret = ERR_PTR(error);
+ goto out;
+ }
error = fuse_handle_backing(feb, &get_fuse_inode(inode)->backing_inode, &fd->backing_path);
- if (error)
- return ERR_PTR(error);
+ if (error) {
+ ret = ERR_PTR(error);
+ goto out;
+ }
get_fuse_inode(inode)->nodeid = feo->nodeid;
- return d_splice_alias(inode, entry);
+ ret = d_splice_alias(inode, entry);
+out:
+ if (feb->backing_file)
+ fput(feb->backing_file);
+ return ret;
}
int fuse_revalidate_backing(struct dentry *entry, unsigned int flags)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index c13be2fa891f..23445c452b45 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1945,7 +1945,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
err = copy_out_args(cs, req->args, nbytes);
fuse_copy_finish(cs);
- if (!err && req->in.h.opcode == FUSE_CANONICAL_PATH) {
+ if (!err && req->in.h.opcode == FUSE_CANONICAL_PATH && !oh.error) {
char *path = (char *)req->args->out_args[0].value;
path[req->args->out_args[0].size - 1] = 0;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 25ddb77d7266..e522ef1af731 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -183,8 +183,10 @@ static bool backing_data_changed(struct fuse_inode *fi, struct dentry *entry,
int err;
bool ret = true;
- if (!entry)
- return false;
+ if (!entry) {
+ ret = false;
+ goto put_backing_file;
+ }
get_fuse_backing_path(entry, &new_backing_path);
new_backing_inode = fi->backing_inode;
@@ -207,6 +209,9 @@ put_bpf:
put_inode:
iput(new_backing_inode);
path_put(&new_backing_path);
+put_backing_file:
+ if (bpf_arg->backing_file)
+ fput(bpf_arg->backing_file);
return ret;
}
#endif
@@ -474,13 +479,18 @@ static void fuse_dentry_canonical_path(const struct path *path,
fuse_canonical_path_backing,
fuse_canonical_path_finalize, path,
canonical_path);
- if (fer.ret)
+ if (fer.ret) {
+ if (IS_ERR(fer.result))
+ canonical_path->dentry = fer.result;
return;
+ }
#endif
path_name = (char *)get_zeroed_page(GFP_KERNEL);
- if (!path_name)
- goto default_path;
+ if (!path_name) {
+ canonical_path->dentry = ERR_PTR(-ENOMEM);
+ return;
+ }
args.opcode = FUSE_CANONICAL_PATH;
args.nodeid = get_node_id(inode);
@@ -495,10 +505,15 @@ static void fuse_dentry_canonical_path(const struct path *path,
free_page((unsigned long)path_name);
if (err > 0)
return;
-default_path:
+ if (err < 0) {
+ canonical_path->dentry = ERR_PTR(err);
+ return;
+ }
+
canonical_path->dentry = path->dentry;
canonical_path->mnt = path->mnt;
path_get(canonical_path);
+ return;
}
const struct dentry_operations fuse_dentry_operations = {
@@ -582,7 +597,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
backing_inode = backing_file->f_inode;
*inode = fuse_iget_backing(sb, outarg->nodeid, backing_inode);
if (!*inode)
- goto bpf_arg_out;
+ goto out;
err = fuse_handle_backing(&bpf_arg,
&get_fuse_inode(*inode)->backing_inode,
@@ -593,8 +608,6 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
err = fuse_handle_bpf_prog(&bpf_arg, NULL, &get_fuse_inode(*inode)->bpf);
if (err)
goto out;
-bpf_arg_out:
- fput(backing_file);
} else
#endif
{
@@ -626,6 +639,8 @@ out_queue_forget:
out_put_forget:
kfree(forget);
out:
+ if (bpf_arg.backing_file)
+ fput(bpf_arg.backing_file);
return err;
}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a1fee82265ea..e76ae9f2671c 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1832,6 +1832,16 @@ void __exit fuse_bpf_cleanup(void);
ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *args);
+static inline int fuse_bpf_run(struct bpf_prog *prog, struct fuse_bpf_args *fba)
+{
+ int ret;
+
+ migrate_disable();
+ ret = BPF_PROG_RUN(prog, fba);
+ migrate_enable();
+ return ret;
+}
+
/*
* expression statement to wrap the backing filter logic
* struct inode *inode: inode with bpf and backing inode
@@ -1883,7 +1893,7 @@ ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *arg
fa.out_numargs = fa.in_numargs; \
\
ext_flags = fuse_inode->bpf ? \
- BPF_PROG_RUN(fuse_inode->bpf, &fa) : \
+ fuse_bpf_run(fuse_inode->bpf, &fa) : \
FUSE_BPF_BACKING; \
if (ext_flags < 0) { \
fer = (struct fuse_err_ret) { \
@@ -1938,7 +1948,7 @@ ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *arg
.size = fa.out_args[i].size, \
.value = fa.out_args[i].value, \
}; \
- ext_flags = BPF_PROG_RUN(fuse_inode->bpf, &fa); \
+ ext_flags = fuse_bpf_run(fuse_inode->bpf, &fa); \
if (ext_flags < 0) { \
fer = (struct fuse_err_ret) { \
ERR_PTR(ext_flags), \
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e1de6b1807dd..c67c6680dc87 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -115,6 +115,10 @@ static void fuse_free_inode(struct inode *inode)
#ifdef CONFIG_FUSE_DAX
kfree(fi->dax);
#endif
+#ifdef CONFIG_FUSE_BPF
+ if (fi->bpf)
+ bpf_prog_put(fi->bpf);
+#endif
kmem_cache_free(fuse_inode_cachep, fi);
}
@@ -125,13 +129,6 @@ static void fuse_evict_inode(struct inode *inode)
/* Will write inode on close/munmap and in all other dirtiers */
WARN_ON(inode->i_state & I_DIRTY_INODE);
-#ifdef CONFIG_FUSE_BPF
- iput(fi->backing_inode);
- if (fi->bpf)
- bpf_prog_put(fi->bpf);
- fi->bpf = NULL;
-#endif
-
truncate_inode_pages_final(&inode->i_data);
clear_inode(inode);
if (inode->i_sb->s_flags & SB_ACTIVE) {
@@ -151,6 +148,15 @@ static void fuse_evict_inode(struct inode *inode)
}
}
+#ifdef CONFIG_FUSE_BPF
+static void fuse_destroy_inode(struct inode *inode)
+{
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ iput(fi->backing_inode);
+}
+#endif
+
static int fuse_reconfigure(struct fs_context *fc)
{
struct super_block *sb = fc->root->d_sb;
@@ -1084,6 +1090,9 @@ static const struct export_operations fuse_export_operations = {
static const struct super_operations fuse_super_operations = {
.alloc_inode = fuse_alloc_inode,
+#ifdef CONFIG_FUSE_BPF
+ .destroy_inode = fuse_destroy_inode,
+#endif
.free_inode = fuse_free_inode,
.evict_inode = fuse_evict_inode,
.write_inode = fuse_write_inode,
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 9ea915e9d2a1..a392e40a89cb 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -699,7 +699,7 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
struct fsnotify_group *group;
struct inode *inode;
struct path path;
- struct path alteredpath;
+ struct path alteredpath = {};
struct path *canonical_path = &path;
struct fd f;
int ret;
@@ -752,6 +752,11 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
if (path.dentry->d_op->d_canonical_path) {
path.dentry->d_op->d_canonical_path(&path,
&alteredpath);
+ if (IS_ERR(alteredpath.dentry)) {
+ ret = PTR_ERR(alteredpath.dentry);
+ goto path_put_and_out;
+ }
+
canonical_path = &alteredpath;
path_put(&path);
}
@@ -763,6 +768,7 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
/* create/update an inode mark */
ret = inotify_update_watch(group, inode, mask);
+path_put_and_out:
path_put(canonical_path);
fput_and_out:
fdput(f);
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 37eba54836d1..c286ab3dcce5 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -93,10 +93,13 @@ static inline int fsnotify_file(struct file *file, __u32 mask)
if (mask & FS_OPEN) {
if (path->dentry->d_op &&
path->dentry->d_op->d_canonical_path) {
- struct path lower_path;
+ struct path lower_path = {};
int ret;
path->dentry->d_op->d_canonical_path(path, &lower_path);
+ if (IS_ERR(lower_path.dentry))
+ return PTR_ERR(lower_path.dentry);
+
ret = fsnotify_parent(lower_path.dentry, mask,
&lower_path, FSNOTIFY_EVENT_PATH);
path_put(&lower_path);